午夜视频在线观看区二区-午夜视频在线观看视频-午夜视频在线观看视频在线观看-午夜视频在线观看完整高清在线-午夜视频在线观看网站-午夜视频在线观看亚洲天堂

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

C# 中的“相等判斷”

freeflydom
2025年3月10日 16:3 本文熱度 342

C# 中判斷相等的方式很多,例如:

  • 雙等號 ==
  • 實例的 Equals() 方法
  • Object.Equals() 靜態方法
  • Object.ReferenceEquals() 方法
  • EqualityComparer<int>.Default.Equals() 方法
  • is 運算符

還有一些特殊的類型內部實現了相等判斷,例如:

  • 元組
  • 匿名類型

還有一些特別的相等判斷,例如:

  • 內部元素結構化相等比較

這些相等判斷都是做什么的?何時使用?下面我將一一列舉說明。

1. 雙等號(==)的相等判斷

1.1 基元類型

對于基元類型(intfloat 等),== 是比較二者值是否相等。查看這些基元類型的源碼可以發現,它們并沒有對 == 運算符進行重載,但它們卻可以使用 == 進行比較。這是因為編譯器對基元類型進行了特殊優化:

  • 編譯階段:直接生成 ceq IL 指令(Compare Equal)
  • 運行時:JIT 編譯器將 ceq 轉換為底層 CPU 的整數比較指令,無需調用任何方法

1.2 部分預定義值類型

部分內置的值類型(非基元類型,如 decimal),它們可以使用 == 進行比較,是因為對 == 運算符進行了重載。下面兩段代碼比較了 int 和 decimal 進行相等比較對應的 IL 代碼:

int num = 1;
int num2 = 2;
bool flag = num == num2;
// 對應的 IL 代碼如下,有刪減
IL_0000: nop
// int num = 1;
IL_0001: ldc.i4.1
IL_0002: stloc.0
// int num2 = 2;
IL_0003: ldc.i4.2
IL_0004: stloc.1
// bool flag = num == num2;
IL_0005: ldloc.0
IL_0006: ldloc.1
IL_0007: ceq
IL_0009: stloc.2
decimal num = 1m;
decimal num2 = 2m;
bool flag = num == num2;
// 對應的 IL 代碼如下,有刪減
IL_0000: nop
// decimal num = 1m;
IL_0001: ldsfld valuetype [System.Runtime]System.Decimal [System.Runtime]System.Decimal::One
IL_0006: stloc.0
// decimal num2 = 2m;
IL_0007: ldloca.s 1
IL_0009: ldc.i4.2
IL_000a: call instance void [System.Runtime]System.Decimal::.ctor(int32)
// bool flag = num == num2;
IL_000f: ldloc.0
IL_0010: ldloc.1
IL_0011: call bool [System.Runtime]System.Decimal::op_Equality(valuetype [System.Runtime]System.Decimal, valuetype [System.Runtime]System.Decimal)
IL_0016: stloc.2

對于值類型,如果沒有重載 == 運算符,是無法使用 == 進行比較的。如下代碼無法通過編譯:

Person person1 = new Person();
Person person2 = new Person();
bool flag = person1 == person2;
struct Person
{
    public int Age { get; set; }
}

1.3 引用類型

對于引用類型,== 判斷返回二者的引用是否為相同(前提是未重載 == 運算符)。最典型的是 string 類型,它的 == 方法判斷兩個字符串內容是否相同,將其強轉為 object 類型再進行 == 比較時,將轉化為引用比較。以如下代碼為例,它將依次輸出 True、False:

string value = "123";
string content1 = value + value;
string content2 = value + value;
Console.WriteLine(content1 == content2);
Console.WriteLine((object)content1 == (object)content2);

上述 string 變量值是在運行時才確定的,因此它們的引用不相同。再看下面這段代碼,它將依次輸出 True、True:

string value = "123";
string content1 = value;
string content2 = value;
Console.WriteLine(content1 == content2);
Console.WriteLine((object)content1 == (object)content2);

這是因為編譯時 string 變量的值已經確定了,為了節省內存,二者是同一實例。

2. Equals() 實例方法

2.1 Equals() 的編寫準則與使用場景

Equals() 實例方法常用于哈希表等需要執行相等判斷的集合類型,因此它對相等判斷的要求更為嚴格。它遵循如下準則:

  • 自反性

    x.Equals(x) 應該為 true

  • 對稱性

    x.Equals(y) 的返回值與 y.Equals(x) 相同。

  • 傳遞性

    x.Equals(y)y.Equals(z) 為 true,則 x.Equals(z) 也應該為 true

  • 一致性

    只要 x 和 y 未被修改,x.Equals(y) 的返回值都應該相同。

  • 非空性

    x.Equals(null) 應返回 false

如果不嚴格遵守上述準則,那么哈希表中的工作就會出錯!假設我們有如下 Person 類,它覆寫了 Equals() 方法,并且始終返回 false,這使得它在插入 HashSet<T> 后,卻無法正確查找。如下代碼將輸出 False:

Person person = new Person
{
    Name = "John",
    Age = 20
};
HashSet<Person> set = new();
set.Add(person);
Console.WriteLine(set.Contains(person));
struct Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public override bool Equals(object obj)
    {
        return false;
    }
}

以上是 Equals() 方法的主要用途(我很少在業務代碼中看到調用 Equals() 方法的),下面我們講解 Euqals() 在值類型、引用類型中的不同。

2.1 基元類型

基元類型的 Equals() 方法直接調用了 == 運算符,因此它的調用和使用 == 運算符沒有差別。

2.1.1 NaN 的相等判斷

在學習 NaN 的相等判斷之前我們先回答一個問題:NaN 是什么?

NaN 是“Not a Number”的縮寫,表示未定義或不可表示的值。它常出現在浮點計算被除數為 0 的情況。如下計算便會得到 NaN:

Console.WriteLine(0.0 / 0.0);

NaN 十分特殊,使用 == 運算符進行判斷和使用 Equals() 進行判斷結果剛好相反!以如下代碼為例,它將分別輸出 False、True

double value = 0.0 / 0.0;
Console.WriteLine(value == value);
Console.WriteLine(value.Equals(value));

這是因為 == 更多的是表示“數學中的相等”,在數學中,兩個 NaN 無論如何都不可能相等,因此 value == value 的結果是 False。而 Equals() 必須支持自反性,因此 value.Equals(value) 的結果是 True。集合和字典需要 Equals() 保持這個行為,否則就無法找到之前存儲的項目了。

我們通常使用 floast.IsNaN() 或 double.IsNaN() 方法判斷一個值是否為 NaN:

Console.WriteLine (double.IsNaN (0.0 / 0.0));

Info

請參考第2章 C# 語言基礎 - hihaojie - 博客園 2.4.7 特殊的浮點值、第6章 框架基礎 - hihaojie - 博客園 6.11.2.6 Equals 和 == 在何時并不等價

2.2 值類型

這里我們特指自定義結構體,其 Equals() 方法未被覆寫。

值類型的 Equals() 方法很特別,它的底層會通過反射對所有字段進行相等比較!以如下代碼為例,即使 p1 和 p2 分別定義,Equals() 方法仍能判斷二者相等。

Person p1 = new Person
{
    Name = "John",
    Age = 18
};
Person p2 = new Person
{
    Name = "John",
    Age = 18
};
Console.WriteLine(p1.Equals(p2));
struct Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

通過反射完成相等判斷,它的性能必然受限,并且值類型在使用 object.Equals() 方法比較時會進行裝箱。為此 C# 提供了 IEquatable<T> 接口。

2.2.1 IEquatable<T> 接口

Info

該內容可參考第4章 類型設計準則 - hihaojie - 博客園的 4.7 struct 的設計、第8章 使用準則 - hihaojie - 博客園的 8.6 IComparable<T> 與 IEquatable<T>、8.9 Object

值類型實現 IEquatable<T> 可以避免 2 個問題:

  1. 值類型的 Object.Equals() 方法會導致裝箱,
  2. Object.Equals() 使用了反射,它的默認實現效率不高。

該接口定義如下,其 Equals() 方法要求我們自行完成成員的相等判斷:

public interface IEquatable<T>
{
    bool Equals(T? other);
}

以前文的 Person 結構體為例,它的實現如下:

Person p1 = new Person
{
    Name = "John",
    Age = 18
};
Person p2 = new Person
{
    Name = "John",
    Age = 18
};
Console.WriteLine(p1.Equals(p2));
class Person : IEquatable<Person>
{
    public string Name { get; set; }
    public int Age { get; set; }
    public override bool Equals(object? obj)
    {
        return Equals(obj as Person);
    }
    public bool Equals(Person? other)
    {
        if (other is null)
        {
            return false;
        }
        if (!Name.Equals(other.Name))
        {
            return false;
        }
        if (Age != other.Age)
        {
            return false;
        }
        return true;
    }
}

2.3 引用類型

對于引用類型(在 Equals() 方法、== 運算符未被覆寫的情況下),其 Equals() 方法與 == 運算符含義相同,比較引用是否相同。

而 Equals 和 == 含義不同這種做法在引用類型中有很多,開發者自定義 Equals() 實現值的相等比較,而仍舊令 == 執行(默認的)引用相等比較。StringBuilder 類便采用了這種方式,如下代碼將輸出“False、True”:

var sb1 = new StringBuilder ("foo");
var sb2 = new StringBuilder ("foo");
Console.WriteLine (sb1 == sb2);
Console.WriteLine (sb1.Equals (sb2));

Notice

StringBuilder 并未覆寫 object.Equals() 實例方法,它只是添加了一個新的重載方法。因此如下兩段代碼執行結果不同:

Console.WriteLine(sb1.Equals(sb2));
Console.WriteLine(((object)sb1).Equals(sb2));

什么情況下應該覆寫引用類型的 Equals() 方法呢?《框架設計指南》第8章 使用準則給出了建議:

  • CONSIDER:如果引用類型表示的是一個值,考慮覆蓋 Equals() 方法以提供值相等語義。

    例如:表示數值、數學實體的引用類型。

Info

更多內容,請參考第6章 框架基礎 - hihaojie - 博客園 6.11.2.6 Equals 和 == 在何時并不等價、第8章 使用準則 8.9.1 Object.Equals

3. Object.Equals() 靜態方法

Object.Equals() 靜態方法主要用于避免“實例為空導致的空引用異常(NullReferenceException)”。它的內部操作如下:

public static bool Equals (object objA, object objB)
    => objA == null ? objB == null : objA.Equals (objB);

與 object.Equals() 實例方法不同,該靜態方法接受兩個參數。它常用于 == 和 != 無法使用的場景,譬如泛型實例比較:

class Test<T>
{
    T _value;
    public void SetValue(T newValue)
    {
        if (!object.Equals(newValue, _value))
        {
            _value = newValue;
            OnValueChanged();
        }
    }
    protected virtual void OnValueChanged() {}
}

上述代碼無法使用 == 和 !=(因為類型不確定,編譯時無法綁定);對于 object.Equals() 實例方法,如果 newValue 為 null,則會拋出 NullReferenceException 異常,因此這里使用靜態方法 Object.Equals()

4. Object.ReferenceEquals() 方法

我們在2.3 引用類型提到:

而 Equals 和 == 含義不同這種做法在引用類型中有很多,開發者自定義 Equals() 實現值的相等比較,而仍舊令 == 執行(默認的)引用相等比較。StringBuilder 類便采用了這種方式,如下代碼將輸出“False、True”:

如果 == 和 Equals() 都進行了重載,我們又需要判斷引用是否相同,應該怎么做?

有 2 種方案:

  • 將實例顯式轉換為 object 再用 == 進行比較
  • 通過 Object.ReferenceEquals() 靜態方法比較

我們實際看 Object.ReferenceEquals() 代碼會發現,上述兩種方案其實是一樣的:都是將實例轉換為 object 再用 == 進行比較,只是實例轉換為 object 這一步通過傳參的方式省略了:

public static bool ReferenceEquals (Object objA, Object objB)
{
        return objA == objB;
}

如下這段代碼對比了各種比較方式,只有最后兩條輸出語句正確進行了引用比較:

var p1 = new Person
{
    Name = "John",
    Age = 18
};
var p2 = new Person
{
    Name = "John",
    Age = 18
};
Console.WriteLine(p1 == p2);
Console.WriteLine(p1.Equals(p2));
Console.WriteLine(((object)p1).Equals(p2));
Console.WriteLine(object.Equals(p1, p2));
Console.WriteLine((object)p1 == (object)p2);
Console.WriteLine(object.ReferenceEquals(p1, p2));
class Person : IEquatable<Person>
{
    public string Name { get; set; }
    public int Age { get; set; }
  
    public static bool operator ==(Person left, Person right)
    {
        return left.Equals(right);
    }
  
    public static bool operator !=(Person left, Person right)
    {
        return !(left == right);
    }
    public override bool Equals(object? obj)
    {
        return Equals(obj as Person);
    }
    public bool Equals(Person? other)
    {
        if (other is null)
        {
            return false;
        }
        if (!Name.Equals(other.Name))
        {
            return false;
        }
        if (Age != other.Age)
        {
            return false;
        }
        return true;
    }
}

5. EqualityComparer<T>.Default.Equals() 方法

我們在3. Object.Equals() 靜態方法的用例代碼中展示了兩個泛型實例比較是否相等:

class Test<T>
{
    T _value;
    public void SetValue(T newValue)
    {
        if (!object.Equals(newValue, _value))
        {
            _value = newValue;
            OnValueChanged();
        }
    }
    protected virtual void OnValueChanged() {}
}

它雖然實現了功能,但性能上仍有部分損耗:如果 T 是值類型,使用 object.Equals() 比較的過程中會發生裝箱!EqualityComparer<T>.Default.Equals() 方法便應運而生。

EqualityComparer<T>.Default 屬性會返回一個通用的相等比較器,替代靜態的 object.Equals 方法。它會首先檢查 T 是否實現了 IEquatable<T>,實現了則直接調用實現類,從而避免裝箱開銷。

如下代碼改為了使用 EqualityComparer<T>.Default.Equals(),避免了裝箱:

class Test<T>
{
    T _value;
    public void SetValue(T newValue)
    {
        if (!EqualityComparer<T>.Default.Equals(newValue, _value))
        {
            _value = newValue;
            OnValueChanged();
        }
    }
    protected virtual void OnValueChanged() { }
}

Info

更多內容,請參考第7章 集合 - hihaojie - 博客園 7.7.1 IEqualityComparer 和 EqualityComparer

6. is 運算符

is 運算符可用的模式有三種:常量模式、類型模式、var模式。這里我們講解常量模式涉及的相等比較。

6.1 常量模式

使用 is 與常量比較相等時,有兩種情況:

  • 整型表達式:使用 == 進行比較
  • 其他類型:使用 object.Equals() 靜態方法進行比較。

6.1.1 整型表達式

整型表達式會轉為使用 == 運算符進行比較。以如下代碼為例,反編譯生成的程序可以看到,它實際使用 == 進行比較:

long x = 10L;
if (x is 10)
{
    Console.WriteLine("x is 10");
}
long x = 10L;
if (x == 10)
{
    Console.WriteLine("x is 10");
}

6.1.2 其他類型

我們可用通過 is 判斷變量是否為 null,此時相等比較使用的是 object.Equals() 方法:

  • 檢查是否為 null,如下例所示:
if (input is null)
{
    return;
}

將表達式與 null 匹配時,編譯器保證不會調用用戶重載的 == 或 != 運算符。

  • 可使用否定模式執行非 null 檢查,如下例所示:
if (result is not null)
{
    Console.WriteLine(result.ToString());
}

Question

請思考如下代碼,會輸出什么內容?符合上述情況中的哪種?

Match(10L);
static void Match(object input)
{
    if (input is 10)
        Console.WriteLine("input 是整型類型的 10");
    else
        Console.WriteLine("Input 不是整型類型的 10");
}

答案是第二種。在傳入 10L 的值時發生了裝箱,因此 input is 10 實際調用了 object.Equals()方法比較相等,顯然,object.Equals(10L, 10) 的結果是 False

6.2 列表模式

  • 從 C#11 開始,可以使用列表模式來匹配列表或數組的元素。 以下代碼檢查數組中處于預期位置的整數值:
int[] empty = [];
int[] one = [1];
int[] odd = [1, 3, 5];
int[] even = [2, 4, 6];
int[] fib = [1, 1, 2, 3, 5];
Console.WriteLine(odd is [1, _, 2, ..]);   // false
Console.WriteLine(fib is [1, _, 2, ..]);   // true
Console.WriteLine(fib is [_, 1, 2, 3, ..]);     // true
Console.WriteLine(fib is [.., 1, 2, 3, _ ]);     // true
Console.WriteLine(even is [2, _, 6]);     // true
Console.WriteLine(even is [2, .., 6]);    // true
Console.WriteLine(odd is [.., 3, 5]); // true
Console.WriteLine(even is [.., 3, 5]); // false
Console.WriteLine(fib is [.., 3, 5]); // true

Info

更多內容,請參考is 運算符 - 將表達式與類型或常量模式匹配 - C# reference | Microsoft Learn 、《深入理解C#》第4版 12.4.1 常量模式、你不知道的C#冷知識(其二)_嗶哩嗶哩_bilibili

7. IEqualityComparer<T> 和 EqualityComparer<T>

提到相等比較必然會談到哈希表。前文我們也提到了 Equals() 方法對哈希表的重要性。如果你有仔細觀察過 HashSet<T> 和 Dictionary<TKey, TValue> 的構造方法,會發現它們都有接收 IEqualityComparer<T> 接口實例的構造器:

public HashSet([Nullable(IEqualityComparer<T>)
public Dictionary(IEqualityComparer<TKey>)

我們從哈希表的原理可知:存放元素時,哈希表通過 GetHashCode() 方法獲取哈希值,將元素存放至相應位置;查找元素時,哈希表通過 GetHashCode() 方法獲取哈希值,獲取元素,再調用 Equals() 方法確認是否為要查找的元素。

有時我們想自定義哈希表的存放、查找規則,便需要使用 IEqualityComparer<T> 接口。該接口定義如下:

public interface IEqualityComparer<in T>
{
    bool Equals(T x, T y);
    int GetHashCode(T obj);
}

接下來我們演示一下該接口的使用。我們假設有 Person 類:

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

我們希望只要 Person 實例的 Name 和 Age 相同,就認為是同一個“人”,下面這段代碼顯然不符合要求,它會輸出 False:

HashSet<Person> set = new HashSet<Person>();
Person person1 = new Person
{
    Name = "John",
    Age = 18
};
set.Add(person1);
Person person2 = new Person
{
    Name = "John",
    Age = 18
};
Console.WriteLine(set.Contains(person2));

如果 Person 是第三方類庫提供的,我們無法覆寫它的 Equals() 方法和 GetHashCode() 方法,這時候我們可以自定義一個類,實現 IEqualityComparer<T> 接口:

class PersonEqualityComParer : IEqualityComparer<Person>
{
    public bool Equals(Person? x, Person? y)
    {
        if (x is null || y is null)
        {
            return false;
        }
        if (x.Name != y.Name)
        {
            return false;
        }
        if (x.Age != y.Age)
        {
            return false;
        }
        return true;
    }
    public int GetHashCode([DisallowNull] Person obj)
    {
        int hash = 17;
        hash = hash * 31 + obj.Name.GetHashCode();
        hash = hash * 31 + obj.Age.GetHashCode();
        return hash;
    }
}

將 PersonEqualityComParer 實例傳入 HashSet 的構造函數,我們便可以自定義哈希表的匹配方式,如下代碼將輸出 True:

HashSet<Person> set = new HashSet<Person>(new PersonEqualityComParer());
Person person1 = new Person
{
    Name = "John",
    Age = 18
};
set.Add(person1);
Person person2 = new Person
{
    Name = "John",
    Age = 18
};
Console.WriteLine(set.Contains(person2));

?

前面講的一大堆都是關于 IEqualityComparer<T> 接口的,那 EqualityComparer<T> 又是做什么的呢?這就不得不提到非泛型版本的 IEqualityComparer 接口。如果你觀察過 HashTable 集合類型(它是非泛型的),會發現它的構造器會可以接受 IEqualityComparer 接口實例:

public Hashtable(IEqualityComparer)

IEqualityComparer 接口的定義和 IEqualityComparer<T> 高度相似:

public interface IEqualityComparer
{
    new bool Equals(object x, object y);
    int GetHashCode(object obj);
}

如果我們想讓前面實現的 PersonEqualityComParer 同時可用于泛型、非泛型哈希表,這兩個接口都需要實現,顯然很麻煩。為此 C# 提供了 EqualityComparer<T> 抽象類,比較器只需實現一次 Equals() 方法、一次 GetHashCode() 方法便可用于泛型、非泛型兩種情況:

// 可同時用于泛型、非泛型哈希表:
HashSet<Person> set = new HashSet<Person>(new PersonEqualityComParer());
Hashtable table = new Hashtable(new PersonEqualityComParer());
class PersonEqualityComParer : EqualityComparer<Person>
{
    public override bool Equals(Person? x, Person? y)
    {
        if (x is null || y is null)
        {
            return false;
        }
        if (x.Name != y.Name)
        {
            return false;
        }
        if (x.Age != y.Age)
        {
            return false;
        }
        return true;
    }
    public override int GetHashCode([DisallowNull] Person obj)
    {
        int hash = 17;
        hash = hash * 31 + obj.Name.GetHashCode();
        hash = hash * 31 + obj.Age.GetHashCode();
        return hash;
    }
}

8. 一些特殊的預定義類型的相等比較

8.1 元組(ValueTuple

元組使用 Equals() 方法和使用 == 運算符比較并不相同。以 ValueTuple<T1, T2> 為例,查看它的源碼可以發現,它的 Equals() 方法通過調用 EqualityComparer<T>.Default.Equals() 實現相等比較:

public bool Equals(ValueTuple<T1, T2> other)
{
    return EqualityComparer<T1>.Default.Equals(Item1, other.Item1)
        && EqualityComparer<T2>.Default.Equals(Item2, other.Item2);
}

如果你在源碼中找不到 == 運算符的重載!但是自 C#7.3 之后,又能使用 ==!= 運算符進行相等判斷。

這是因為編譯器就為元組類型提供了元組 == 和 != 的實現。編譯器將 == 運算符擴展到元素級別的 == 操作。它會對每一對元素值執行 == 操作(!= 運算符同理)。代碼示例如下:

var t1 = (x: "x", y: "y", z: 1);    // 比較時不考慮
var t2 = ("x", "y", 1);             // 元素名稱不同
Console.WriteLine(t1 == t2);
Console.WriteLine(t1.Item1 == t2.Item1 &&   //
                  t1.Item2 == t2.Item2 &&   // 編譯器生成的
                  t1.Item3 == t2.Item3);    // 等價代碼
Console.WriteLine(t1 != t2);
Console.WriteLine(t1.Item1 != t2.Item1 ||   //
                  t1.Item2 != t2.Item2 ||   // 編譯器生成的
                  t1.Item3 != t2.Item3);    // 等價代碼

這也要求元組中的類型必須能通過 ==!= 進行比較,以如下代碼為例,因 Person 結構體未重載 ==!= 運算符,如下代碼編譯器報錯 CS0019:

var tuple1 = (1, p1);
var tuple2 = (1, p2);
Console.WriteLine(tuple1 == tuple2);
struct Person
{
    public int Age;
    public string Name;
}

8.2 匿名類型

匿名類型本質上是引用類型,因此它可以使用 == 運算符進行比較,它比較的是引用是否相等。它的 Equals() 方法則會比較所有元素是否相同(通過 EqualityComparer<T>.Default.Equals() 方法),考慮到它常用于 LINQ,Equals() 比較所有元素是否相同的行為就非常合理了。

兩個匿名類型實例相同的前提是:類型相同、屬性名稱相同、屬性順序相同。以如下代碼為例,它將輸出 True、False、False、False

var value1 = new { Name = "John", Age = 18 };
var value2 = new { Name = "John", Age = 18 };
var value3 = new { Age = 18, Name = "John" };
var value4 = new { Title = "John", Level = 18 };
Console.WriteLine(value1.Equals(value2));
Console.WriteLine(value1.Equals(value3));
Console.WriteLine(value1.Equals(value4));
Console.WriteLine(value1 == value2);

Tips

為什么說“考慮到匿名類型常用于 LINQ,Equals() 比較所有元素是否相同的行為就非常合理了”?

以如下代碼為例,我們通過匿名類型在一個查詢中基于多個鍵進行連接查詢,這就用到了匿名類型的 Equals() 方法:

from s in stringProps
join b in builderProps on new { s.Name, s.PropertyType }
                   equals new { b.Name, b.PropertyType }

9. 內部元素結構化相等比較

有些類型的數據我們需要對內部元素進行相等比較,如數組、元組。此時可用通過 IStructuralEquatable 接口的 Equals() 方法執行該操作。數組和元組實現了該接口。下面是兩個簡單用例,分別演示了對數組、元組內部元素的相等比較:

int[] nums1 = [1, 2, 3, 4, 5];
int[] nums2 = [1, 2, 3, 4, 5];
Console.WriteLine(nums1.Equals(nums2));
IStructuralEquatable se = (IStructuralEquatable)nums1;
Console.WriteLine(se.Equals(nums2, EqualityComparer<int>.Default));
var t1 = (1, "foo");
var t2 = (1, "FOO");
IStructuralEquatable se1 = t1;
Console.WriteLine(se1.Equals(t2, StringComparer.InvariantCultureIgnoreCase));

轉自https://www.cnblogs.com/hihaojie/p/18761086/c-bk2f6


該文章在 2025/3/10 16:03:34 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved

主站蜘蛛池模板: 国产一区中文 | 99久久久久精品一级毛片 | 2025久久精品永久免费 | 1024国产精品自拍 | 国产麻豆视频网站 | 高潮喷水的毛片 | 91精品啪在线观看国产日本 | 91蜜桃视 | 成人午夜动漫在线观看 | 国产一区二区三区在线看片 | 911精品国产一区二区在线 | 国产高潮白浆无码 | 国产美女极品免费视频 | 精品丝袜国产自在在线 | 国产精品国色综合 | 成人片黄网站a毛片 | 国色天香精品一卡2卡3卡 | 国产午夜福利电影在线观看 | 国产女性精品一区二区三区 | 91大片淫黄大片在线天堂 | 高清国产无码乱伦 | 东京热无码人妻一区二区三区av | 丰满少妇熟乱xx | 国产福利小视频91 | 韩国精品视频一区二区在线播放 | av中文字幕网站 | 国产无套粉嫩白浆 | 精品久久久久久中文字幕无码软件 | 国内自拍天天操天天干 | 国产福利精品一区二区无码 | 丰满爆乳少妇中文无码 | 99精品一区无码在线观看 | 99精品视频九九精品视频 | 国产成人av大片在线播放 | 99久久无码免费国产 | 成人自慰女黄网站免费大全 | 成人午夜视频精品一区 | 国产91久久麻豆黄片 | 国产精品不卡在线 | av国产熟女丰满熟女 | 18禁无遮挡无码啪啪网站 |