文章關(guān)鍵字:如何學(xué)習(xí)c#語言,c#語言學(xué)習(xí),c#語言學(xué)習(xí)心得,集成學(xué)習(xí)環(huán)境,c#語言,c#語言學(xué)習(xí)網(wǎng)站,學(xué)習(xí)c#,c#語言學(xué)習(xí)資料,c#語言學(xué)習(xí)方法,c語言學(xué)習(xí)軟件:vs2008,怎樣學(xué)習(xí)c#,怎么學(xué)習(xí)c#,c#書書籍學(xué)習(xí), 學(xué)習(xí)c#的方法 c#學(xué)習(xí),c#學(xué)習(xí)資料,c#筆記
第一部分 基礎(chǔ)知識
一綜合理論知識:
1首先轉(zhuǎn)換成中間語言MSIL(任何語言都可以轉(zhuǎn)換成MSIL)
2利用JIT編譯器(just in time)將中間語言代碼編譯,我們只要關(guān)注用我們熟悉的語言寫程序,其他的工作完全交給系統(tǒng)了
二c#基本語法:
1c#中的空格
c#中空格被忽略,只能識別一個(gè)空格,多個(gè)空格會被忽略,所以一行中可以有多個(gè)空格
2c#中的注意事項(xiàng)
一個(gè)語句之后必須有分號
3注釋
略
4占位符的使用
Console.Writeline("{0}{1}",mystring, myInteger);
每個(gè)占位符用包含在花括號中的一個(gè)整數(shù)來表示,整數(shù)以0開始,每次遞增1,占位符的總數(shù)應(yīng)等于列表中指定的變量數(shù),該列表用逗號分隔開,跟在字符串后面,
表示用后面的變量代替
例二
Console.WriterLine("sourceVar val:{0}",sourceVar);
這里注意占位符的位置
5轉(zhuǎn)義符號的應(yīng)用
1
myString="This string has a/nline break";
輸入為
This string has a
line break
(程序中/n前面和后面都沒有空格就可以實(shí)現(xiàn)轉(zhuǎn)義符的功能)
2
常用轉(zhuǎn)義字符表:
/' 單引號
/" 雙引號
// 反斜杠
/0 空
/a 警告(產(chǎn)生鳴響)
/b 退格
/f 換頁
/n 換行
/r 回車
/t 水平制表符
/v 垂直制表符
6變量的命名
1
字母,下劃線,@都可以作為開頭,要特別注意@,這是新增加的
2
嚴(yán)格區(qū)分大小寫
3
c#中一般采用受單詞大寫的方法來定義類名,變量名,例如Age firstName WinterOfDiscoutent
7常用數(shù)據(jù)類型
整數(shù)部分
sbyte 8 -128 127
byte 8 0 255
short 16 -32768 32767
ushort 16 0 65535
int 32 -2147483648 2147483647(10位,負(fù)的21億到正21億)
uint 32 0 4294967295
long 64 -9223372036854775808 9223372036854775807(19位)
ulong 64 0 18446744073709551615(20位)
要會記憶:
short int和long都是有符號的整數(shù)
ushort uint和ulong是無符號的整數(shù)
上面放在一起記憶,byte和sbyte單獨(dú)記憶,注意byte是無符號的整數(shù)
小數(shù)部分
float
double
decimal
(位數(shù)太多,略)
另外三個(gè)
Char 一個(gè)Unicode字符,0 65535
bool 只有連個(gè)值 true false
string 字符串,其字符個(gè)數(shù)沒有上限,因?yàn)樽址梢允褂每勺兇笮〉膬?nèi)存
(char和ushort都是表示0到65535)
8 C#支持的類型
值類型
變量直接包含它們自己的數(shù)據(jù)
局部變量總是放在棧(stack)中
引用類型
變量間接指向它們的數(shù)據(jù)
局部變量指向堆(heap)中的對象
值類型 包括:
1簡單類型(如 char、int 和 float)
2用戶自定義類型:
枚舉類型enum
結(jié)構(gòu)類型struct。
其區(qū)別是簡單類型可以有字面表達(dá)式,例如42
引用類型 包括:
類 (Class) 類型、
接口類型interface、
委托類型delegate(有的書籍稱代表)
數(shù)組類型[]array。
值類型與引用類型的區(qū)別在于值類型的變量直接包含其數(shù)據(jù),而引用類型的變量則存儲對象引用。對于引用類型,兩個(gè)變量可能引用同一個(gè)對象,因此對一個(gè)變量的操作可能影響另一個(gè)變量所引用的對象。對于值類型,每個(gè)變量都有自己的數(shù)據(jù)副本,對一個(gè)變量的操作不可能影響另一個(gè)變量
9標(biāo)識符起名的規(guī)則:
局部變量、局部常量、非公有實(shí)例域、函數(shù)參數(shù)使用camelCase規(guī)則;
其他類型的標(biāo)識符使用PascalCase規(guī)則。
camelCase規(guī)則(第一個(gè)單詞的首字母小寫,其余單詞的首字母大寫)
PascalCase規(guī)則(所有單詞的首字母大寫)
盡量不要使用縮寫。
Message,而不要使用msg。
不要使用匈牙利命名法。
public sealed class GrammarHelper
{ ...
public QualifiedSymbol Optional(AnySymbol symbol)
{ ... }
private AnyMultiplicity optional =
new OptionalMultiplicity();
}
10 @-c#新引進(jìn)的
int @int = 42; 在關(guān)鍵字前加@來使它可以用作變量名:
string quote = @"""quote""";如果你要在字符串中包含雙引號,那你可以這樣
11編程風(fēng)格
較正規(guī)的編程風(fēng)格
在一個(gè)二元操作符的每一邊都加一個(gè)空格
在每一個(gè)逗號后面而不是前面加一個(gè)空格
每一個(gè)關(guān)鍵字后面加一個(gè)空格
一行一個(gè)語句
分號前不要有空格
函數(shù)的園括號和參數(shù)之間不加空格
在一元操作符和操作數(shù)之間不加空格
在一個(gè)二元操作符的每一邊都加一個(gè)空格:
Console.WriteLine("{0}", result / 13); //推薦
Console.WriteLine("{0}", result/13); //不推薦
在每一個(gè)逗號后面而不是前面加一個(gè)空格:
Console.WriteLine("{0}", result / 13); //推薦
Console.WriteLine("{0}",result / 13); //不推薦
每一個(gè)關(guān)鍵字后面加一個(gè)空格:
if (OneLine(comment)) ... //推薦
if(OneLine(comment)) ... //不推薦
分號前不要有空格:
Console.WriteLine("{0}", result / 13); //推薦
Console.WriteLine("{0}", result / 13) ; //不推薦
函數(shù)的園括號和參數(shù)之間不加空格:
if (OneLine(comment)) ... //推薦
if (OneLine( comment )) ... //不推薦
在一元操作符和操作數(shù)之間不加空格:
++keywordCount; //推薦
++ keywordCount; //不推薦
找錯
bool checked;
... 1
public static void main()
{ ... } 2
int matched = symbol.Match(input)
if (matched > 0)
{
....
} 3
char optional = "?";
string theory = 'complex'; 4
int matched = 0_or_more(symbol);
... 5
第1段程序的錯誤:checked是一個(gè)關(guān)鍵字
第2段程序的錯誤:不是main,而是Main
第3段程序的錯誤:變量聲明語句沒有分號
第4段程序的錯誤:字符值必須用單引號表示,字符串必須用雙引號表示
第5段程序的錯誤:第一個(gè)錯誤是標(biāo)識符不能以數(shù)字開頭;第二個(gè)錯誤是不能用下劃線作標(biāo)識符。
12操作符
1基礎(chǔ)知識
分類
一元操作符
二元操作符
三元操作符
三元操作符只有一個(gè) ?:
括號 (x)
訪問成員 x.y
函數(shù)調(diào)用 f(x)
訪問數(shù)組(不是元素) a[x]
自增 x++
自減 x--
調(diào)用構(gòu)造函數(shù) new
獲得類名 typeof
獲得尺寸 sizeof(不安全的)
數(shù)值檢查 (un)checked
2 is 操作符
3 as 操作符
13操作符的優(yōu)先級
14連接
規(guī)則1
除了賦值操作符外的其他二元操作符都是左連接的。
x+y+z 應(yīng)理解為 (x+y)+z
規(guī)則2
賦值操作符和?: 操作符是右連接的。
x=y=z 應(yīng)理解為 x=(y=z)
x+=y+=z 應(yīng)理解為 x+=(y+=z)
a?b:c?d:e 應(yīng)理解為 a?b:(c?d:e
三類型轉(zhuǎn)換
1隱式轉(zhuǎn)換
對于隱式轉(zhuǎn)換 規(guī)則:任何類型A,只要其取值范圍完全包含在類型B的取值范圍內(nèi),
就可以隱式轉(zhuǎn)換為類型B
由于char和ushort數(shù)字范圍一樣,因此可以將char隱式轉(zhuǎn)換成ushort,但是
反過來就不行,即不能將ushort隱式轉(zhuǎn)換成char
轉(zhuǎn)換表
略
2顯示轉(zhuǎn)換
第一種方法
利用 (變量類型)這種方式實(shí)現(xiàn) 例子:
略
顯示轉(zhuǎn)換要注意溢出,如果要轉(zhuǎn)換的值過大,超出類型的表示范圍,則會出現(xiàn)溢出而導(dǎo)致錯誤
第二種方法
利用Convert命令
這種方法有一定的限制 規(guī)則:在字符串向double轉(zhuǎn)換的時(shí)候,字符串必須是數(shù)字的有效表達(dá)方式
,該數(shù)字必須是不會溢出的數(shù)。
數(shù)的表達(dá)方式:首先是一個(gè)可選符號(加號或減號),然后是零位或多位數(shù)字,一個(gè)圓點(diǎn)后跟一位或多位數(shù)字,接著是一個(gè)可選的e或E,例如
-1.323e-43
轉(zhuǎn)換表
略
復(fù)雜點(diǎn)的例子
略
四枚舉類型
1
我們知道連續(xù) 和離散 的感念
對于double,其就可以看作是連續(xù)的
而bool就是離散的,其只有兩個(gè)值true false
枚舉就是給變量一個(gè)范圍,這個(gè)范圍是離散的值組成的集合
它是一個(gè)用戶聲明的值類型
enum Suit
{
Clubs, Diamonds, Hearts, Spades
}
//Suit表示一副牌,它有4個(gè)花色:梅花(Clubs),方塊(Diamonds),紅心(Hearts),//黑桃(Spades)
sealed class Example
{
static void Main()
{
...
Suit lead = Spades; //錯誤
...
Suit trumps = Suit.Clubs; //正確
枚舉的聲明可以出現(xiàn)在類聲明的相同地方。
枚舉的聲明包括名字、訪問權(quán)限、內(nèi)在的類型和枚舉的成員。
枚舉中聲明的常量的范圍是定義它們的枚舉,換言之,下面的例子是錯誤的:
Suit trumps = Clubs;
Clubs必須被限制為Suit的一個(gè)成員,就如下面:
Suit trumps = Suit.Clubs;
枚舉的注意點(diǎn)
枚舉值缺省為int
你可以選擇任一內(nèi)在的整數(shù)類型
但不能是字符型
enum Suit : int //內(nèi)在類型是int,可以省略
{
Clubs,
Diamonds,
Hearts = 42, //成員的取值缺省為前一個(gè)成員取值+1,但可以自己賦初值
Spades, //最后一個(gè)分號是可選的
};//可以有結(jié)尾分號
枚舉類可以顯式的聲明它的內(nèi)在類型是sbyte, byte, short, ushort, int, uint, long, ulong。
如果一個(gè)枚舉類沒有顯式聲明它的內(nèi)在類型,則缺省為int。
成員的取值必須和枚舉聲明的內(nèi)在類型相同,并且必須在內(nèi)在類型的范圍之內(nèi)
(例如,你不能讓成員的取值為負(fù)數(shù),而枚舉的內(nèi)在類型是uint)。
如果成員沒有被賦值, 那么它的取值是前一個(gè)成員取值+1,第一個(gè)成員的缺省值是1。
枚舉的成員的取值可以有相同的取值。
最后一個(gè)枚舉成員可以使用一個(gè)結(jié)尾分號,這使得你將來可以很方便地加入更多的成員。
枚舉成員的訪問權(quán)限隱含為public。
2枚舉的計(jì)算
枚舉的計(jì)算和整數(shù)計(jì)算一樣
using system
enum Weekday
{
Sunday,Monday,Wednesday,Thurday,Friday,Sunday
};
class Test
{
public static void Main()
{
Weekday day1 = Weekday.Sunday;
Weekday day2 = Weekday.Saturday;
Weekday day3 = day1 + 6;
}
}
3枚舉的轉(zhuǎn)換
五數(shù)組類型
六結(jié)構(gòu)類型
七語句
throw語句
throw語句拋出錯誤
檢查先前定義的條件時(shí)非常有用
表達(dá)式的類型必須是System.Exception或是它的派生類
string DaySuffix(int days)
{
if (days < 0 || days > 31)
{
throw new
ArgumentOutOfRangeException("days");
}
...
}
語句列表和塊語句
static void Main()
{
F();
G();
{
H();
I();
}
}
標(biāo)記語句和 goto 語句
static void Main(string[] args)
{
if (args.Length == 0)
goto done;
Console.WriteLine(args.Length);
done:
Console.WriteLine("Done");
}
局部常數(shù)聲明
static void Main()
{
const float pi = 3.14f;
const int r = 123;
Console.WriteLine(pi * r * r);
}
局部變量聲明
static void Main()
{
int a;
int b = 2, c = 3;
a = 1;
Console.WriteLine(a + b + c);
}
表達(dá)式語句
static int F(int a, int b)
{
return a + b;
}
static void Main()
{
F(1, 2); // Expression statement
}
if 語句
static void Main(string[] args)
{
if (args.Length == 0)
Console.WriteLine("No args");
else
Console.WriteLine("Args");
}
switch 語句
static void Main(string[] args)
{
switch (args.Length)
{
case 0:
Console.WriteLine("No args");
break;
case 1:
Console.WriteLine("One arg ");
break;
default:
int n = args.Length;
Console.WriteLine("{0} args", n);
break;
}
}
while 語句
static void Main(string[] args)
{
int i = 0;
while (i < args.Length)
{
Console.WriteLine(args[i]);
i++;
}
}
do mhile 語句
static void Main()
{
string s;
do
{
s = Console.ReadLine();
} while (s != "Exit");
}
for 語句
static void Main(string[] args)
{
for (int i = 0; i < args.Length; i++)
Console.WriteLine(args[i]);
}
foreach 語句
tatic void Main(string[] args)
{
foreach (string s in args)
Console.WriteLine(s);
}
break 語句
static void Main(string[] args)
{
int i = 0;
while (true)
{
if (i == args.Length)
break;
Console.WriteLine(args[i++]);
}
}
continue 語句
static void Main(string[] args)
{
int i = 0;
while (true)
{
Console.WriteLine(args[i++]);
if (i < args.Length)
continue;
break;
}
}
return 語句
static int F(int a, int b)
{
return a + b;
}
static void Main()
{
Console.WriteLine(F(1, 2));
return;
}
throw 語句和 try 語句
static int F(int a, int b)
{
if (b == 0)
throw new Exception("Divide by zero");
return a / b;
}
static void Main()
{
try
{
Console.WriteLine(F(5, 0));
}
catch(Exception e)
{
Console.WriteLine("Error");
}
}
checked 和 unchecked 語句
static void Main()
{
int x = Int32.MaxValue;
Console.WriteLine(x + 1); // Overflow
checked
{
Console.WriteLine(x + 1); // Exception
}
unchecked
{
Console.WriteLine(x + 1); // Overflow
}
}
lock 語句
static void Main()
{
A a = ...;
lock(a)
{
a.P = a.P + 1;
}
}
using statements
static void Main()
{
using (Resource r = new Resource())
{
r.F();
}
}
八異常處理
類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類
第二部分 類的基礎(chǔ)知識
類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類
一綜合
1 類的修飾符
public 表示不限制對類的訪問
protected 表示只能從所在類和所在類的派生自類進(jìn)行訪問
internal 表示只有所在類才能訪問
private 只有系統(tǒng)定義的庫或者包才能訪問
abstract 抽象類,不允許建立類的實(shí)例
sealed 密封類 不允許被繼承
2 類的成員
成員常量
字段
屬性
方法
事件
索引
構(gòu)造函數(shù)
析構(gòu)函數(shù)
3 this關(guān)鍵字的使用
二命名空間
三裝箱和拆箱
四變量
靜態(tài)變量與非靜態(tài)變量(又稱實(shí)例變量)
變量的類型:
靜態(tài)static variables
非靜態(tài) instance variables
數(shù)組元素 array elements
值參數(shù) value parameters
引用參數(shù) reference parameters
輸出參數(shù) output parameters
局部變量 local variables
局部變量是指在一個(gè)獨(dú)立的程序塊中聲明的變量,如for switch using等
它只在該范圍內(nèi)有效
局部變量 和其他變量不一樣 系統(tǒng)不會給它指明一個(gè)默認(rèn)值
五屬性與字段(有的教材叫域)
1字段
字段類似c++中的簡單成員變量例如:
class A
{
public int x;
publicstring y;
private flort z;
}
2靜態(tài)字段和非靜態(tài)字段
1
和前面講的講臺變量和非靜態(tài)變量的用法 原理 一樣
若將一個(gè)字段說明為靜態(tài)的,無論建立多少類的實(shí)例,內(nèi)存中只有一個(gè)靜態(tài)數(shù)據(jù)的拷貝
當(dāng)這個(gè)類的第一個(gè)實(shí)例被初始化時(shí),靜態(tài)字段就被初始化了,以后再次建立實(shí)例的時(shí)候
不再對其初始化,所有的類的實(shí)例共享一個(gè)靜態(tài)字段副本
與靜態(tài)字段相反,非靜態(tài)字段在類每次進(jìn)行實(shí)例化的時(shí)候,每個(gè)實(shí)例都有一份單獨(dú)的拷貝
下面例子顯示了一個(gè) Color 類,
它包含三個(gè)分別名為 redPart、bluePart 和 greenPart 的內(nèi)部實(shí)例字段
和四個(gè)分別名為 Red、Blue、Green 和 White 的靜態(tài)字段
class Color
{
public static Color Red = new Color(0xFF, 0, 0);
public static Color Blue = new Color(0, 0xFF, 0);
public static Color Green = new Color(0, 0, 0xFF);
public static Color White = new Color(0xFF, 0xFF, 0xFF);
internal ushort redPart;
internal ushort bluePart;
internal ushort greenPart;
public Color(ushort red, ushort blue, ushort green)
{
redPart = red;
bluePart = blue;
greenPart = green;
}
}
2
readonly的相關(guān)知識
3屬性 get set
1概述
屬性的引進(jìn),體現(xiàn)了對象的封裝性:不直接操作了的數(shù)據(jù)內(nèi)容,而是通過訪問其對其訪問
利用get 和set 對屬性進(jìn)行讀 寫
只有set訪問器 表明屬性的值只能進(jìn)行設(shè)置吧不能讀出
只有g(shù)et訪問器 表明屬性的值只讀 不能改寫
同時(shí)具有set和get訪問器 表明屬性的值 讀寫 都是允許的
get 要和 return 結(jié)合使用 來讀取屬性的值
set 要和 value 結(jié)合使用來設(shè)置屬性的值
2 get 語句舉例:
必須返回一個(gè)有確定類型的值
功能上就像一個(gè) “get 函數(shù)”
struct Time
{
...
public int Hour
{
get
{
return hour;
}
...
}
private int hour, minute, second;
}
Time lunch = new Time();
... Console.WriteLine(lunch.Hour);
//請注意,get和set不是關(guān)鍵字
當(dāng)讀一個(gè)屬性的時(shí)候,屬性的get語句自動運(yùn)行。
get語句必須返回一個(gè)有確定類型的值。在上面的例子中,Time結(jié)構(gòu)類有一個(gè)整型屬性Hour,所以它的get語句必須返回一個(gè)整型值。
屬性的返回值不能是void(從這里可以推斷出字段的類型也不能是void)。這就意味著get語句必須包含一個(gè)完整的return語句(retun;這種形式是錯誤的)。
get語句可以在retun語句前包含任何其他的語句(比如,可以檢查變量的類型),但return語句不能省略。
注意,get和set不是關(guān)鍵字,所以你可以在任何地方包括get/set語句中聲明一個(gè)局部變量、常量的名字是get或set,但最好不要這樣做
3 set 語句舉例:
是通過value 標(biāo)識符來進(jìn)行賦值的
可以包含任何語句(甚至沒有語句)
struct Time
{
...
public int Hour
{
...
set {
if (value < 0 || value > 24)
throw new ArgumentException("value");
hour = value;
}
}
private int hour, minute, second;
}
Time lunch = new Time();
...
lunch.Hour = 12;
當(dāng)寫一個(gè)屬性的時(shí)候,屬性的set語句自動運(yùn)行。
在上面的例子中,Time結(jié)構(gòu)類有一個(gè)整型屬性Hour,所以賦給這個(gè)屬性的值必須是一個(gè)整型值。例如:
lunch.Hour = 12;
把一個(gè)整型值12賦給了lunch的Hour屬性,這個(gè)語句會自動調(diào)用屬性的set語句。
set語句是通過value標(biāo)識符來獲得屬性的賦值的。例如,如果12被賦給了Hour屬性,那么vaue的值就是12。
注意的是value不是一個(gè)關(guān)鍵字。value只是在set語句中才是一個(gè)標(biāo)識符。你可以在set語句外的任何語句聲明value為一變量的名字。
例如:
public int Hour
{
get { int value; ... }//正確
set { int value; ... }//錯誤
}
4只讀屬性
只讀屬性只有g(shù)et語句
任何寫操作都會導(dǎo)致錯誤
就像一個(gè)只讀字段
struct Time
{
...
public int Hour
{
get
{
return hour;
}
}
private int hour, minute, second;
}
Time lunch = new Time();
...
lunch.Hour = 12; //錯誤
...
lunch.Hour += 2;//錯誤
一個(gè)屬性可以不必同時(shí)聲明get語句和set語句。你可以只聲明一個(gè)get語句。在這種情況下,屬性是只讀的,任何寫的操作都會導(dǎo)致錯誤。例如,下面的語句就會導(dǎo)致一個(gè)錯誤:
lunch.Hour = 12;
因?yàn)镠our是只讀屬性。
但要注意的是,屬性必須至少包括一個(gè)get或set語句,一個(gè)屬性不能是空的:
public int Hour { }//錯誤
5只寫屬性
只寫屬性只能有set 語句
任何讀操作都是錯誤的
struct Time
{
...
public int Hour
{
set {
if (value < 0 || value > 24)
throw new OutOfRangeException("Hour");
hour = value;
}
}
private int hour, minute, second;
}
Time lunch = new Time();
...
Console.WriteLine(lunch.Hour); //錯誤
...
lunch.Hour += 12;//錯誤
一個(gè)屬性可以不必同時(shí)聲明get語句和set語句。你可以只聲明一個(gè)set語句。在這種情況下,屬性是只寫的,任何讀的操作都會導(dǎo)致錯誤。例如,下面的語句就會導(dǎo)致一個(gè)錯誤:
Console.WriteLine(lunch.Hour);
因?yàn)镠our是只寫屬性。
而下面的例子則看上去好像是對的:
lunch.Hour += 2;
這句語句的實(shí)際運(yùn)作是這樣的:
lunch.Hour = lunch.Hour + 2;
它執(zhí)行了讀的操作,因此是錯誤的。因此,像+=這種復(fù)合型的賦值操作符既不能用于只讀屬性,也不能用于只寫屬性。
6綜合舉例
在下面的示例中,Button 類定義一個(gè) Caption 屬性。
public class Button
{
private string caption;
public string Caption
{
get
{
return caption;
}
set
{
caption = value;
Repaint();
}
}
}
可讀取并寫入的屬性(如 Caption)同時(shí)包含 get 和 set 訪問器。
當(dāng)讀取屬性值時(shí)調(diào)用 get 訪問器;當(dāng)寫入屬性值時(shí)則調(diào)用 set 訪問器。
在 set 訪問器中,屬性的新值是通過一個(gè)名為 value 的隱式參數(shù)來賦值的。
屬性聲明相對直接一些,但是屬性的實(shí)際值在它們被使用時(shí)才可見。
例如,讀取和寫入 Caption 屬性的方式可以與讀取和寫入字段相同:
Button b = new Button();
b.Caption = "ABC"; // set; causes repaint
string s = b.Caption; // get
b.Caption += "DEF"; // get & set; causes repaint
六方法(函數(shù))
所有的函數(shù)必須在類內(nèi)部聲明
無源文件和頭文件之分
所有的函數(shù)必須聲明的時(shí)候被實(shí)現(xiàn)
函數(shù)不能有結(jié)尾分號
sealed class Methods
{
void Inline()
{ ...
}
void Error()
{ ...
}; //錯誤,函數(shù)不能有結(jié)尾分號
C#允許可以在類的聲明中加入結(jié)尾分號,例如:
sealed class Methods
{
...
};//可以有結(jié)尾分號
但是,C#不允許在函數(shù)的聲明中加入結(jié)尾分號,例如:
sealed class Methods
{
void NotAllowed() {...} ; //錯誤,函數(shù)不能有結(jié)尾分號
}
2函數(shù)重載
一個(gè)類中的函數(shù)可以有同一個(gè)名字,稱為重載
函數(shù)名和參數(shù)稱為標(biāo)識
標(biāo)識必須唯一
和C++與Java一樣,C#允許一個(gè)類聲明兩個(gè)以上的同名函數(shù),只要參數(shù)的類型或個(gè)數(shù)不同。這就是重載。
但是,一個(gè)類不能包含標(biāo)識為相同的實(shí)例函數(shù)和靜態(tài)函數(shù)
namespace System
{
public sealed class Console
{
public static void WriteLine()
{ ... }
public static void WriteLine(int value)
{ ... }
public static void WriteLine(double value)
{ ... }
...
public static void WriteLine(object value)
{ ... }
...
}
}
注意:
和C++與Java一樣,返回值的類型不是標(biāo)識的一部分,不能被用作重載的標(biāo)準(zhǔn),例如:
sealed class AlsoIllegal
{
int Random() { ... }
double Random() { ... }//錯誤
3ref和out重載
ref / out 在大部分情況下是標(biāo)識的一部分!
你可以重載一個(gè)ref型參數(shù)和一個(gè)普通參數(shù)
你可以重載一個(gè)out型參數(shù)和一個(gè)普通參數(shù)
你不可以重載一個(gè)ref型參數(shù)和一個(gè)out型參數(shù)
影子博客sealed class Overloading
{
void Allowed( int parameter)
{ ... }
void Allowed(ref int parameter)
{ ... }
//正確,重載一個(gè)ref型參數(shù)和一個(gè)普通參數(shù)
void AlsoAllowed( int parameter)
{ ... }
void AlsoAllowed(out int parameter)
{ ... }
//正確,重載一個(gè)out型參數(shù)和一個(gè)普通參數(shù)
void NotAllowed(ref int parameter)
{ ... }
void NotAllowed(out int parameter)
{ ... }
//錯誤,不能重載一個(gè)ref型參數(shù)和一個(gè)out型參數(shù)
}
ref和out修飾符可以是一個(gè)函數(shù)的標(biāo)識。但是你不能同時(shí)重載ref和out型參數(shù)。
ref和out修飾符在某種意義上是“安全的“,因?yàn)橹挥衦ef型實(shí)參才能傳遞給ref型函數(shù)參數(shù),
只有out型實(shí)參才能傳遞給out型函數(shù)參數(shù)。
但是,當(dāng)調(diào)用函數(shù)的時(shí)候,你會非常容易忘記ref和out修飾符,所以最好不要重載ref和out型參數(shù)。
例如:
sealed class Overloading
{
public static void Example(int parameter)
{ ... }
public static void Example(ref int parameter)
影子博客{ ... }
static void Main()
{
int argument = 42;
Example(argument);//在這兒非常容易忘記ref修飾符
}
}
4方法中的參數(shù)
1
總說:
值參數(shù)
輸出參數(shù)out 用out修飾
數(shù)組行參數(shù) 用params修飾
2
值參數(shù):
沒有被ref 或 out修飾的函數(shù)參數(shù)是一個(gè)值型參數(shù)。
值型參數(shù)只有在該參數(shù)所屬的函數(shù)被調(diào)用的時(shí)候才存在,并且用調(diào)用時(shí)所傳遞的實(shí)參的值來進(jìn)行初始化。
當(dāng)函數(shù)調(diào)用結(jié)束時(shí),值型參數(shù)不復(fù)存在
只有被預(yù)先賦值的實(shí)參才能被傳遞給值型參數(shù),例如:
int arg; // arg沒有被賦初值
Method(arg);//錯誤,實(shí)參必須預(yù)先賦初值
傳遞給函數(shù)的實(shí)參可以是純粹的數(shù)而不是變量,例如:
Method(42);
3
引用型參數(shù)
引用型參數(shù)是實(shí)參的一個(gè)別名
沒有發(fā)生復(fù)制
實(shí)參必須預(yù)先被賦值
實(shí)參必須是一個(gè)變量類型
實(shí)參和函數(shù)參數(shù)都要有ref
sealed class ParameterPassing
{
static void Method(ref int parameter)
{
parameter = 42;
}
static void Main()
{
int arg = 0;
Console.Write(arg); //結(jié)果為0
Method(ref arg);
Console.Write(arg); //結(jié)果為42
}
}
函數(shù)參數(shù)有ref修飾符時(shí),被稱為引用型參數(shù)。引用型參數(shù)不產(chǎn)生新的存儲區(qū)間。實(shí)際上,引用型參數(shù)是函數(shù)調(diào)用時(shí)所傳遞的實(shí)參所代表的變量的別名。結(jié)果是引用型參數(shù)只是實(shí)參所代表的變量的另一個(gè)名字。
ref修飾符必須同時(shí)出現(xiàn)在函數(shù)聲明語句和函數(shù)調(diào)用語句中。
只有被預(yù)先賦值的實(shí)參才能被傳遞給引用型參數(shù),例如:
影子博客int arg; // arg沒有被賦初值
Method(ref arg);//錯誤,實(shí)參必須預(yù)先賦初值
傳遞給引用型參數(shù)的實(shí)參必須是變量類型,而不能是純粹的值或常量。
Method(ref 42); //錯誤,引用型參數(shù)的實(shí)參不能是純粹的值
const int arg = 42;
Method(ref arg); //錯誤,引用型參數(shù)的實(shí)參不能是常量
4
out型參數(shù)
out型參數(shù)是實(shí)參的一個(gè)別名
沒有發(fā)生復(fù)制
實(shí)參不必預(yù)先賦值
實(shí)參必須是變量類型
函數(shù)參數(shù)必須被預(yù)先賦值才能使用
實(shí)參和函數(shù)參數(shù)都要有out
影子博客sealed class ParameterPassing
{
static void Method(out int parameter)
{
parameter = 42;
}
static void Main()
{
int arg;
//Console.Write(arg);
Method(out arg);
Console.Write(arg); //結(jié)果為42
}
}
函數(shù)參數(shù)有out修飾符時(shí),被稱為out型參數(shù)。out型參數(shù)不產(chǎn)生新的存儲區(qū)間。實(shí)際上,out型參數(shù)是函數(shù)調(diào)用時(shí)所傳遞的實(shí)參所代表的變量的別名。結(jié)果是out型參數(shù)只是實(shí)參所代表的變量的另一個(gè)名字。
out修飾符必須同時(shí)出現(xiàn)在函數(shù)聲明語句和函數(shù)調(diào)用語句中。
沒有被預(yù)先賦值的實(shí)參能夠被傳遞給引用型參數(shù),例如:
int arg; // arg沒有被賦初值
Method(out arg);//正確,實(shí)參可以不賦初值
傳遞給out型參數(shù)的實(shí)參必須是變量類型,而不能是純粹的值或常量。
Method(out 42); //錯誤,out型參數(shù)的實(shí)參不能是純粹的值
const int arg = 42;
Method(out arg); //錯誤,out型參數(shù)的實(shí)參不能是常量
5
ref與out區(qū)別
ref:
static void Main()
{
int arg = 0; //ref必須要初始化,在用,而out不用初始化
Console.Write(arg);
Method(ref arg);
Console.Write(arg);
}
out:
static void Main()
{
int arg;
Method(out arg); //沒有初始化
Console.Write(arg);
}
6
參數(shù)數(shù)組
參數(shù)數(shù)組用 params 修飾符聲明。
一個(gè)給定的方法只能有一個(gè)參數(shù)數(shù)組,而且它必須始終是最后一個(gè)指定的參數(shù)。
參數(shù)數(shù)組的類型總是一維數(shù)組類型。
using System;
class Test
{
static void F(params int[] args) {
Console.WriteLine("# of arguments: {0}", args.Length);
for (int i = 0; i < args.Length; i++)
Console.WriteLine("\targs[{0}] = {1}", i, args[i]);
}
static void Main() {
F();
F(1);
F(1, 2);
F(1, 2, 3);
F(new int[] {1, 2, 3, 4});
}
}
顯示了帶數(shù)目可變的 int 參數(shù)的方法 F,以及對此方法的若干個(gè)調(diào)用。輸出為:
# of arguments: 0
# of arguments: 1
args[0] = 1
# of arguments: 2
args[0] = 1
args[1] = 2
# of arguments: 3
args[0] = 1
args[1] = 2
args[2] = 3
# of arguments: 4
args[0] = 1
args[1] = 2
args[2] = 3
args[3] = 4
5靜態(tài)成員與非靜態(tài)成員
若將類中的某個(gè)成員聲明為static
該成員成為靜態(tài)成員
類中的成員要么是靜態(tài),要么是非靜態(tài)的
非靜態(tài)成員為實(shí)例專用,只有被實(shí)例化了
非靜態(tài)成員才有意義
靜態(tài)成員在內(nèi)存中只有一個(gè)區(qū)域,而非靜態(tài)成員與類的實(shí)例聯(lián)系在一起,每當(dāng)創(chuàng)建一個(gè)實(shí)例,系統(tǒng)會為創(chuàng)建 的實(shí)例創(chuàng)建一個(gè)非靜態(tài)成員
這樣在內(nèi)存區(qū)域中有多個(gè)副本
5靜態(tài)與非靜態(tài)方法
理解這個(gè)靜態(tài)方法 可以聯(lián)想 Console.WriteLine() 這個(gè)方法就是靜態(tài)的
七委托
八索引
九事件
十自動內(nèi)存管理
類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類
第三部分 OOP技術(shù)
類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類類
一構(gòu)造函數(shù)與析構(gòu)函數(shù)
二接口
一個(gè)接口定義了一個(gè)協(xié)議。一個(gè)實(shí)現(xiàn)了一個(gè)接口的類或結(jié)構(gòu)必須符合它的協(xié)議。一個(gè)接口可以從多個(gè)基本接口繼承,而一個(gè)類或結(jié)構(gòu)也可以實(shí)現(xiàn)多個(gè)接口。
接口可以包含方法、屬性、事件和索引。一個(gè)接口不能包含常數(shù)、域、操作符、構(gòu)造函數(shù)、靜態(tài)構(gòu)造函數(shù)或類型,也不能包括任何類型的靜態(tài)成員。所有接口成員隱含的都有公共訪問。接口成員聲明中包含任何修飾符是錯誤的. 接口成員不能被用abstract, public, protected, internal, private, virtual, override, 或 static 修飾符聲明
// 用接口用了這么久,今天才知道接口也可以聲明屬性,索引器和事件。
//真是罪過~~
//提示:在VS中,把光標(biāo)定位在下面一行的ITest中,按alt+shit+F10,可以自動實(shí)現(xiàn)接口
interface ITest
{
//聲明事件
event Mydelegate MyEvent;
//聲明屬性
string Str { set; get; }
//聲明索引器
string this[int i] { set; get; }
//聲明方法
void test(int t);
}
//注意代理要聲明在命名空間下,接口外
public delegate void Mydelegate(string str);
接口自己不為它所定義的成員提供執(zhí)行程序。接口只是指定必須被實(shí)現(xiàn)這個(gè)接口的類或接口提供的成員。
1.1 接口聲明
一個(gè)接口聲明是一個(gè)類型聲明 (§9.5) 它聲明了新的接口類型。
interface-declaration:attributesopt interface-modifiersopt interface identifier interface-baseopt interface-body ;opt
一個(gè)接口聲明由下面的方式組成:一個(gè)可選的屬性集合, 跟著一個(gè)可選的接口修飾符集合, 跟著關(guān)鍵詞interface 和一個(gè)命名接口的標(biāo)識符,還可以跟著一個(gè)可選的接口基本說明,跟著一個(gè)接口主體,最后可以選擇跟一個(gè)分號
接口修飾符\interface-modifier:newpublicprotectedinternalprivate
對于相同的修飾符在一個(gè)接口聲明中出現(xiàn)多次是錯誤的。
new 修飾符是在嵌套接口中唯一被允許存在的修飾符。它說明用相同的名稱隱藏一個(gè)繼承的成員 public, protected, internal和private 修飾符控制接口的訪問能力。根據(jù)發(fā)生接口聲明的上下文,只有這些修飾符中的一些會被允許
1.1.2 基本接口
一個(gè)接口可以從零或多個(gè)接口繼承,那些被稱為這個(gè)接口的顯式基本接口。當(dāng)一個(gè)接口有比零多的顯式基本接口時(shí),那么在接口的聲明中的形式為,接口標(biāo)識符后面跟著由一個(gè)冒號和一個(gè)用逗號分開的基本接口標(biāo)識符列表。
interface-base:: interface-type-list
一個(gè)接口的顯式基本接口必須可訪問。例如,在一個(gè)公共接口的基本接口中指定一個(gè)私有接口是錯誤的。
1、C#中的接口是單獨(dú)于類來定義的。這和 C++模型是對立的,在 C++中接口實(shí)際上就是抽象基類。
2、接口和類都能夠繼承多個(gè)接口。
3、而類能夠繼承一個(gè)基類,接口根本不能繼承類。
一個(gè)接口直接或間接地從它自己繼承是錯誤的。
接口方法
接口方法使用接口方法聲明(interface-method-declaration)來聲明:
interface-method-declaration:attributesopt newopt return-type identifier (formal-parameter-listopt);
接口方法聲明中的屬性(attributes), 返回類型(return-type), 標(biāo)識符(identifier), 和 形式參數(shù)列表(formal-parameter-lis)t 與一個(gè)類的方法聲明中的那些有相同的意義。一個(gè)接口方法聲明不允許指定一個(gè)方法主體,而聲明通常用一個(gè)分號結(jié)束。
C#中的接口1.都是“虛的”不能被實(shí)例化,這也是接口中為什么不能包含字段--成員變量的原因2.正因?yàn)榻涌谑翘摰?所以接口內(nèi)的索引,屬性,時(shí)間等只能有聲明,而不能在接口內(nèi)實(shí)現(xiàn),具體如何實(shí)現(xiàn)是派生接口或者派生類的事.3.都具有模板的性質(zhì),如果一個(gè)接口或者類從某一個(gè)接口繼承,它將自動具有被集成者的特征(包括索引,屬性,函數(shù),實(shí)踐等).4.接口支持多重繼承,而C#中,類之支持單一繼承,接口實(shí)際表示的是一種承載能力,
對接口成員的訪問對接口方法的調(diào)用和采用索引指示器訪問的規(guī)則與類中的情況也是相同的。如果底層成員的命名與繼承而來的高層成員一致,那么底層成員將覆蓋同名的高層成員。但由于接口支持多繼承,在多繼承中,如果兩個(gè)父接口含有同名的成員,這就產(chǎn)生了二義性(這也正是C#中取消了類的多繼承機(jī)制的原因之一),這時(shí)需要進(jìn)行顯式的定義:interface ISequence
{
int Count { get; set; }
}
interface IRing
{
void Count(int i) ;
}
interface IRingSequence: ISequence, IRing { }
class CTest
{
void Test(IRingSequence rs)
{
//rs.Count(1) ; 錯誤, Count 有二義性
//rs.Count = 1; 錯誤, Count 有二義性
((ISequence)rs).Count = 1; // 正確
((IRing)rs).Count(1) ; // 正確調(diào)用IRing.Count
}
}
//上面的例子中,前兩條語句rs .Count(1)和rs .Count = 1會產(chǎn)生二義性,從而導(dǎo)致編譯時(shí)錯誤,
//因此必須顯式地給rs 指派父接口類型,這種指派在運(yùn)行時(shí)不會帶來額外的開銷。
//再看下面的例子:
interface IInteger
{
void Add(int i) ;
}
interface IDouble
{
void Add(double d) ;
}
interface INumber: IInteger, IDouble {}
class CMyTest
{
void Test(INumber Num)
{
// Num.Add(1) ; 錯誤
Num.Add(1.0) ; // 正確
((IInteger)n).Add(1) ; // 正確
((IDouble)n).Add(1) ; // 正確
}
}
//調(diào)用Num.Add(1) 會導(dǎo)致二義性,因?yàn)楹蜻x的重載方法的參數(shù)類型均適用。
//但是,調(diào)用Num.Add(1.0) 是允許的,
//因?yàn)?.0 是浮點(diǎn)數(shù)參數(shù)類型與方法IInteger.Add()的參數(shù)類型不一致,
//這時(shí)只有IDouble.Add 才是適用的。
//不過只要加入了顯式的指派,就決不會產(chǎn)生二義性。