繁体   English   中英

关于 C# 中的包含和等于

[英]Regarding Contains and Equals in C#

新手来了我在 Microsoft 文档中阅读了以下代码。 您可以在此处查看网页: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.find?view=net-6.0

public class Part : IEquatable<Part>
{
    public string PartName { get; set; }
    public int PartId { get; set; }

    
    //other code

    public override bool Equals(object obj)
    {
        if (obj == null) return false;
        Part objAsPart = obj as Part;
        if (objAsPart == null) return false;
        else return Equals(objAsPart);
    }
    

    // other code

    public bool Equals(Part other)
    {
        if (other == null) return false;
        return (this.PartId.Equals(other.PartId));
    }
    
}

public class Example
{
    public static void Main()
    {
        // Create a list of parts.
        List<Part> parts = new List<Part>();

        // Add parts to the list.
        parts.Add(new Part() { PartName = "crank arm", PartId = 1234 });
        parts.Add(new Part() { PartName = "chain ring", PartId = 1334 });
        parts.Add(new Part() { PartName = "regular seat", PartId = 1434 });
        parts.Add(new Part() { PartName = "banana seat", PartId = 1444 });
        parts.Add(new Part() { PartName = "cassette", PartId = 1534 });
        parts.Add(new Part() { PartName = "shift lever", PartId = 1634 }); ;

        //other code

        // Check the list for part #1734. This calls the IEquatable.Equals method
        // of the Part class, which checks the PartId for equality.
        Console.WriteLine("\nContains: Part with Id=1734: {0}",
            parts.Contains(new Part { PartId = 1734, PartName = "" }));

     }
}

现在,我的问题是关于parts.Contains(new Part { PartId = 1734, PartName = "" })行。 这是ListT.Contains(T)方法。

正如您从 Microsoft 参考源(此处: https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,521b9f7129105e15 )中看到的, Contains方法的代码如下:

public bool Contains(T item) {
            if ((Object) item == null) {
                for(int i=0; i<_size; i++)
                    if ((Object) _items[i] == null)
                        return true;
                return false;
            }
            else {
                EqualityComparer<T> c = EqualityComparer<T>.Default;
                for(int i=0; i<_size; i++) {
                    if (c.Equals(_items[i], item)) return true;
                }
                return false;
            }
        }

所以你可以看到Contains方法使用Equals方法,但是哪个Equals呢? c.Equals(_items[i], item)表示我们调用的方法属于EqualityComparer<T>.Default 实际上, DefaultEqualityComparer<T> class 的属性,它返回相同 class 的 object。 所以我们这里看到的Equals应该属于EqualityComparer<T> class。

问题 #1:我们如何拥有EqualityComparer<T> class 的 object,因为这个 class 是抽象的?

问题 #2:我们如何调用c.Equals(_items[i], item)因为这个方法也是抽象的? (如您所见: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.equalitycomparer-1.equals?view=net-6.0

But the most important of all, Question #3: How do we go from c.Equals(_items[i], item) method of class EqualityComparer<T> , to the IEquatable.Equals method which is implemented in the Part class. 第一种方法会调用第二种方法吗?

这里: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.equalitycomparer-1?view=net-6.0它说如下:

Default属性检查类型T是否实现了System.IEquatable<T>泛型接口,如果是,则返回调用IEquatableT.Equals方法实现的EqualityComparer<T> 。否则,它返回EqualityComparer<T> ,由T提供。”

我不明白如何调用第二种方法IEquatable.Equals

我很抱歉发了这么长的帖子。 提前致谢!

我们怎么能有一个EqualityComparer<T> class 的 object 因为这个 class 是抽象的?

你没有,你有一个在EqualityComparer<T>.CreateComparer方法中创建的 EqualityComparer<T EqualityComparer<T>继承者的实例。

问题 #2:我们如何调用c.Equals(_items[i], item)因为这个方法也是抽象的?

导致EqualityComparer<T>的具体继承者应该并实现此方法(阅读有关abstract keyword 的文档)。 文档中稍作修改的示例可能会澄清一些事情:

// create an instance of Square and save to variable of Square type:
Square square = new Square(12); 
// assign Square to variable of Shape type, works cause Square is Shape:
Shape shape = square; 
// access the abstract method declared on Shape and implemented by Square:
Console.WriteLine($"Area of the square = {shape.GetArea()}");

abstract class Shape
{
    public abstract int GetArea();
}

class Square : Shape
{
    private int _side;

    public Square(int n) => _side = n;

    // GetArea method is required to avoid a compile-time error.
    public override int GetArea() => _side * _side;
}

Question #3: How do we go from c.Equals(_items[i], item) method of class EqualityComparer<T> , to the IEquatable.Equals method which is implemented in the Part class. 第一种方法会调用第二种方法吗?

因为已经提到的CreateComparer方法检查泛型类型T是否实现了这个接口,如果它实现了 - 使用Default实例中的实现:

// If T implements IEquatable<T> return a GenericEqualityComparer<T>
if (typeof(IEquatable<T>).IsAssignableFrom(t)) {
     return (EqualityComparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(GenericEqualityComparer<int>), t);
}

一些额外的注意事项:

  • 为了更好地理解这是如何工作的,您可能需要阅读有关 generics 的信息: 此处此处此处的一些重要信息
  • referencesource.microsoft.com is for the older .NET Framework sources, if you are working with modern .NET Core (including .NET 5, .NET 6 and upcoming .NET 7) you can use source.dot.net

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM