C#匿名類型(Anonymous Type)學習日記


當我們不要定義復雜的方法,事件,構造函數這樣復雜的類的時候,可以動態的生成一個自定義的數據類型 --> 匿名類型。

 

1.定義匿名類型

定義一個匿名類型時,需要用到 var 關鍵字和對象初始化語法。

var : 編譯器會在編譯時自動生成新類定義(我們無法在C#代碼中看到類的名稱)。

初始化:它將告訴編譯器為新創建的類型創建私有的后台字段和(只讀的)屬性。

 

通過傳遞參數構建一個匿名類型,並打印相關信息

private static void BiuldAnonymousType(string make, string color, int currSp)
{
    // 使用傳入參數構建匿名類型
    var car = new { Make = make, Color = color, CurrSp = currSp };

    // 獲取屬性數據
    Console.WriteLine($"{car.Color} 的 {car.Make} 時速{car.CurrSp}");

    // 匿名類型包含對System.Object中每個虛方法(virtual)的自定義實現
    Console.WriteLine($"ToString={car.ToString()}");
}

 

調用:也可以使用硬編碼構建匿名類型

public static void Show()
{
    Console.WriteLine("fun with anonymous types");

    // 注意 匿名類型也可以使用硬編碼創建
    // 構建一個匿名對象表示汽車
    var car = new { Make = "honda", Color = "blue", CurrSp = 180 };

    // 輸出顏色和車
    Console.WriteLine($"我的車是{car.Color}{car.Make}");

    // 調用輔助方法通過參數創建匿名類型
    BiuldAnonymousType("baoma", "white", 220);
}

 

2.匿名類型的內部表示方式

所有的匿名類型都自動繼承Object,所以我們可以在 car 對象上ToString,GetHashCode,Equals,我們嘗試調用一下:

private static void ReflectOverAnonymousType(object obj)
{
    Console.WriteLine($"對象實例:{obj.GetType().Name}");
    Console.WriteLine($"類型: {obj.GetType().Name} 基類: {obj.GetType().BaseType}");
    Console.WriteLine($"toString():{obj.ToString()}");
    Console.WriteLine($"getHashCode():{obj.GetHashCode()}");
}

 

調用以及結果:

public static void Show()
{
    Console.WriteLine("fun with anonymous types");

    // 構建一個匿名對象表示汽車
    var car = new { Make = "honda", Color = "blue", CurrSp = 180 };

    ReflectOverAnonymousType(car);
}

 

car對象的類型是:<>f__AnonymousType0`3(你的或許不同),匿名類型名稱由編譯器覺得,我們無從干涉,CIL代碼。

 

 3.方法 ToString() 和 GetHashCode() 的實現

1.ToString()

public override string ToString()
{
    StringBuilder builder = new StringBuilder();
    builder.Append("{ Color = ");
    builder.Append(this.<Color>i_Field);
    builder.Append(", Make = ");
    builder.Append(this.<Make>i_Field);
    builder.Append(", CurrSp = ");
    builder.Append(this.<CurrSp>i_Field);
    builder.Append("}");
    return builder.ToString();
}

 

2.GetHashCode()

它使用每個匿名類型的變量計算出散列值作為System.Collections.Generic.EqualityComparer<T>的類型輸入,僅當兩個匿名類型有相同的屬性並且被賦予了相同的值,才會產生相同的散列值。

 

4.匿名類型的相等語義

Equals()

private static void EqualityTest()
{
    // 構建兩個匿名類型,擁有相同的名稱/值對
    var oneCar = new { Make = "honda", Color = "blue", CurrSp = 180 };
    var twoCar = new { Make = "honda", Color = "blue", CurrSp = 180 };

    // 調用Equals
    if (oneCar.Equals(twoCar))
    {
        Console.WriteLine("Equals“同一個匿名對象");
    }
    else
    {
        Console.WriteLine("Equals“不是 同一個匿名對象");
    }

    // 使用 == 操作符
    if (oneCar == twoCar)
    {
        Console.WriteLine("==“同一個匿名對象");
    }
    else
    {
        Console.WriteLine("==“不是 同一個匿名對象");
    }

    // 比較對象類型
    if (oneCar.GetType().Name == twoCar.GetType().Name)
    {
        Console.WriteLine("同一個類型");
    }
    else
    {
        Console.WriteLine("不同類型");
    }

    ReflectOverAnonymousType(oneCar);
    ReflectOverAnonymousType(twoCar);
}

 分析一下這樣的結果:

1.Equals():編譯器重寫Equals()在判斷對象相等時使用了基於值得語義(如:筆記兩個對象的每一個數據成員的值)

2.==操作符:是因為匿名類型沒有重載 相等操作符(==,!=),所以==比較的是引用,而不是內容。

3.GetType():是因為如果我們同一程序集中聲明兩個相同的(屬性相同)匿名類型,編譯器只會生成一個匿名類型的定義。

 

5.包含匿名類型的匿名類型

var order = new
{
    car = new { Make = "honda", Color = "blue", CurrSp = 180 },
    price = 200000
};

ReflectOverAnonymousType(order);

 

總結:

其實,我們應該謹慎使用匿名類型,尤其在使用LINQ時,永遠不要因為匿名類型的出現而放棄使用強類型的類或結構。

其實,匿名類型本身有許多限制:

  • 你並沒有控制匿名類型的名稱
  • 匿名類型繼承System.Object
  • 匿名類型的字段和屬性總是只讀的
  • 匿名類型不支持事件,自定義方法,自定義操作符和自定義重寫
  • 匿名類型是隱式封閉的(implicit sealed)
  • 匿名類型的實體創建只使用默認構造函數

如果,我們需要快速定義一個實體的形狀,而不需要定義其功能時,可以使用匿名類型。

 

學無止境,望各位看官多多指教。


免責聲明!

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



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