C#支持的運算符
https://msdn.microsoft.com/zh-cn/library/6a71f45d(v=vs.140).aspx
checked 和 unchecked
byte b = 255; b++; Console.WriteLine(b);
byte數據類型 范圍 0~255。遞增 b 的值會導致溢出。CLR如何處理這個溢出取決於很多因素,包括編譯器選項。
可以使用代碼塊標記 checked,發生溢出,拋出 OverflowException 異常。
byte b = 255; checked { b++; } Console.WriteLine(b);
也可以用 /checked 編譯器選項進行編譯,就可以檢查程序中所有未標記代碼中的溢出。
反之 unchecked 不檢查溢出,注意 unchecked 是默認行為。
byte b = 255; unchecked { b++; } Console.WriteLine(b);
is運算符
檢查對象是否是該該類型,或者派生自該類型。
int value = 25; Console.WriteLine( (value is int) + " " + (value is object));
as 運算符
執行引用類型的顯示類型轉換。如果類型不兼容,返回null。
object str = "Hello"; object value = 12; string str1 = str as string; string value2 = value as string;
value2 等於 null
sizeof運算符
確定在棧中值類型需要的字節大小。
Console.WriteLine( sizeof(int) );
如果是復雜類型(和非基本類型)使用sizeof運算符,需要放在 unsafe 代碼塊中。
unsafe { Console.WriteLine(sizeof(Customer)); }
typeof 運算符
返回表示特定類型的 System.Type 對象。如 typeof(string) 返回表示 System.String 類型的Type對象。
可空類型運算符
int? v1 = null; int? a = v1 + 2; // a = null
空合並運算符
int? v1 = null; v1 = v1 ?? 10; Console.WriteLine(v1);
運算符優先級
一般情況避免利用運算符優先級來生成正確結果,用圓括號指定運算符執行順序。
類型安全
中間語言(IL)對代碼實現強制實現強類型。
強類型語言在沒有強制類型轉換前,不允許兩種不同類型的變量相互操作。
類型轉換
byte byte1 = 10; byte byte2 = 20; byte count = byte1 + byte2; Console.WriteLine(count);
這里編譯時,提示您 byte count 改成 int count。只是因為 兩個 byte類型 相加 返回 int 類型,這時就需要類型轉換了。
1、隱式轉換
只要能保證值不會發生任何變化,類型轉換就開自動(隱式)進行。
long count = byte1 + byte2;
2、顯示轉換類型
byte count =(byte) (byte1 + byte2);
要小心的時候顯示轉換類型,還要注意防止丟失數據。更不能轉換 null 。
如果要 字符串 轉換 為 int 時
string str = "100"; int i = int.Parse(str); str = i.ToString();
裝箱和拆箱
裝箱用於描述把一個值類型轉換為引用類型。
拆箱把引用類型轉換為值類型。
比較引用類型的相等性
ReferenceEquals
兩個版本 Equals
比較運算符(==)
1、ReferenceEquals
ReferenceEquals是一個靜態方法,測試兩個引用類的同一個實例,判斷兩個引用是否包含內存中的相同地址。
2、虛函數 Equals
因為是虛函數,所以需要在類中重寫它,比較。比較方式可以通過值。如果需要用類的實例用作字典中的鍵,那么需要重寫 Object.GetHashCode() 的方式,注意此方式效率非常低的。
3、靜態函數 Equals
有兩個參數,如果兩個引用實際上引用了某個對象,它就調用虛函數 Equals 實例方法。這表示重寫了 虛函數 Equals ,也重寫了靜態版本函數。
4、比較運算符 ==
比較值和比較引用。
ReferenceEquals 用於比較引用,Equals 用於比較值,比較運算符看作一個中間項。ReferenceEquals應用值類型時,總是返回false。因為值類型需要裝箱到對象中。
System.ValueType 提供的 Equals 的默認重寫版本肯定足以應付絕大多數自定義的結構,但仍可以針對自己的接口再次重寫它,以提供性能。
運算符重載
重載不僅僅限於算術運算符。還可以 重載比較運算符 ==、< 。等 語句 if(a==b) 默認比較引用,對於 string,比較字符串是否相同。
struct Vector { public double x, y, z; public Vector(double x, double y, double z) { this.x = x; this.y = y; this.z = z; } public Vector(Vector rhs) { x = rhs.x; y = rhs.y; z = rhs.z; } public override string ToString() { return x + " " + y + " " + z; } public static Vector operator +(Vector lhs, Vector rhs) { Vector result = new Vector(lhs); result.x += rhs.x; result.y += rhs.y; result.z += rhs.z; return result; } public static Vector operator *(Vector lhs, double rhs) { return new Vector(rhs * lhs.x, rhs * lhs.y, rhs * lhs.z); } }
一般運算符左邊參數命名 lhs,運算符右邊命名 rhs。
Vector vector1, vector2, vector3; vector1 = new Vector(4.0, 3.0, 1.0); vector2 = new Vector(4.0, -3.0, -1.0); vector3 = vector1 + vector2; Console.WriteLine(vector3);
與C++語言不同,C#不允許重載 "=" 運算符,但如果重載 "+" 運算符,編譯器自動使用 "+" 運算符的重載執行 += 勻速符操作。
比較運算符重載
- == 和 !=
- > 和 <
- >= 和 <=
如果重載了 "==",就必須重載 "!=" 。另外,比較運算符必須返回布爾類型的值。
重載 "==" 和 "!=" 時,必須重載 System.Object 中繼承 Equals 和 GetHashCode 方法,否則會產生一個編譯警告。原因是Equals方法實現與"=="運算符相同類型的相等邏輯。
public static bool operator ==(Vector lhs, Vector rhs) { if (lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z) { return true; } else { return false; } } public static bool operator !=(Vector lhs, Vector rhs) { return !(lhs == rhs); } public override bool Equals(object obj) { return base.Equals(obj); } public override int GetHashCode() { return base.GetHashCode(); }
用戶自定義的類型強制重載
c#允許定義自己的數據類型(結構和類),並可以在自定義數據類型之間進行類型強制轉換。
public static implicit operator float(Currency value) { return (float) value; }
這里定義的類型強制轉換可以隱式地把Currency型的值轉換為float型。
implicit 聲明 數據類型轉換為隱式的,編譯器就可以隱式或顯式的使用這個轉換。
explicit 聲明為顯式的使用它。
public static explicit operator Celsius(Fahrenheit fahr) { return new Celsius((5.0f / 9.0f) * (fahr.degrees - 32)); } Fahrenheit fahr = new Fahrenheit(100.0f); Console.Write("{0} Fahrenheit", fahr.Degrees); Celsius c = (Celsius)fahr;
類型強制轉換必須同時聲明為 public 和 static。
https://msdn.microsoft.com/zh-cn/library/xhbhezf4.aspx
C++中,類型強制轉化針對於類的實例成員。
示例
struct Currency { public uint Dollars; public ushort Cents; public Currency(uint dollars, ushort cents) { this.Dollars = dollars; this.Cents = cents; } public override string ToString() { return string.Format("${0}.{1,-2:00}", Dollars,Cents); } // 隱式轉換 public static implicit operator float(Currency value) { return value.Dollars + (value.Cents / 100.0f); } // 顯示轉換 public static explicit operator Currency(float value) { uint dollars = (uint)value; ushort cents = (ushort)((value - dollars) * 100); return new Currency(dollars, cents); } } static void Main(string[] args) { try { Currency balance = new Currency(50,35); Console.WriteLine(balance); // 轉換為 float Console.WriteLine("balance is " + balance); // 隱式調用 toString Console.WriteLine("balance is (using ToString()) " + balance.ToString()); // 顯示調用 toString float balance2 = balance; // 隱式轉為 float Console.WriteLine("After converting to float, = " + balance2); balance = (Currency) balance2; // 顯示轉為 Currency Console.WriteLine("After converting back to Currency, = " + balance); Console.WriteLine("Now attempt to convert out of range value of " + "-$50.50 to a Currency:"); checked { balance = (Currency)(-50.50); // 顯示轉為 Currency Console.WriteLine("Result is " + balance.ToString()); } } catch(Exception e) { Console.WriteLine("Exception occurred: " + e.Message); } Console.ReadLine(); }
類型轉換的語法對於結構和類一樣的。
類之間的類型強制轉換
定義不同結構或類的實例之間的類型強制是完全合法,也有限制:
- 如果某個類派生自另一個類,就不能定義這兩個類之間的類型強制轉換(因為這些類型轉換已存在)。
- 類型強制必須在源數據類型或目標數據類型的內部定義。
C#要求把類型強制轉換的定義放在源類或目標類的內部。因為這樣可以防止第三方類型強制轉換引入類中。
基類和派生類之間的類型強制轉換
MyBase 和 MyDerived。其中 Myderived 直接或間接派生自 MyBase 類。
MyDerived derivedObject = new MyDerived(); MyBase baseCopy = derivedObject;
MyDerived 隱式地強制轉換為 MyBase
MyBase derivedObject = new MyDerived(); MyBase baseObject = new MyBase(); MyDerived derivedCopy1 = (MyDerived) derivedObject; // OK MyDerived derivedCopy2 = (MyDerived) baseObject; // Throws exception
基類是不可以強制轉為派生類。
裝箱和拆箱數據類型強制轉換
object derivedObject = new Currency(40); object baseObject = new object(); Currency derivedCopy1 = (Currency) derivedObject; // OK Currency derivedCopy2 = (Currency) baseObject; // Throws exception
多重類型轉換
Currency balance = new Currency(10); long amount = (long) balance; double amountD = balance;
Currency 定義了一個 float 的隱式轉換,編譯器又知道如何顯式地從 float 強制轉換為 long。所以 IL代碼 首先把 balance 轉換為 float,在把結果轉換 long。類似這樣。
long amount = (long) (double)balance;