C# 運算符和類型強制轉換(6) 持續更新


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;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM