匿名类型成员平等

Anonymous Type Member Equality

我相信下面的代码应该生成相同匿名类型的两个实例,具有相同顺序的属性,具有相同的名称、类型和值。

    static void Main(string[] args)
    {
        var letterFreq1 = CountLetters("aabbbc");  
        var letterFreq2 = CountLetters("aabbbc");  

        if (letterFreq1.Equals(letterFreq2))
            Console.WriteLine("Is anagram");
        else
            Console.WriteLine("Is not an anagram");
        
    }
    public static object CountLetters(string input) => input.ToCharArray()
                                                            .GroupBy(x => x)
                                                            .Select(x => new {Letter = x.Key, Count = x.Count()})
                                                            .OrderBy(x => x.Letter)
                                                            .ToList();

根据 MS 文档:

If two or more anonymous object initializers in an assembly specify a sequence of properties that are in the same order and that have the same names and types, the compiler treats the objects as instances of the same type. They share the same compiler-generated type information.

Because the Equals and GetHashCode methods on anonymous types are defined in terms of the Equals and GetHashCode methods of the properties, two instances of the same anonymous type are equal only if all their properties are equal.

我将此解释为我应该在 letterFreq1 和 letterFreq2 上获得平等,但这并没有发生。任何人都可以确定为什么平等检查失败吗?我试图避免手动比较 属性 值。

这是一个 但没有帮助解决我的问题。

非常感谢。

I believe the following code should generate two instances of the same anonymous type

不,它生成两个 List<T> 的实例,内容相同。

所以当你执行这个时:

if (letterFreq1.Equals(letterFreq2))

您在 List<T> 对象上调用 .Equals 方法,它不会覆盖从 System.Object 继承的方法,因此进行引用比较。

然而,你是对的,因为匿名类型 比较相等,并且两个列表实际上具有相同的内容,但列表对象不自己做内容比较,所以他们会比较不同。

如果你要哄编译器把两者转换成同一类型的集合,比如:

var letterFreq1 = CountLetters("aabbbc") as IEnumerable<object>;
var letterFreq2 = CountLetters("aabbbc") as IEnumerable<object>;

那你可以比较一下他们的内容:

if (letterFreq1.SequenceEqual(letterFreq2))

但是您首先需要知道它们是集合,因此根据 general/generic 您的代码应该如何,这可能是也可能不是适合您的解决方案。


然而,我真正的建议是在这种情况下避免使用匿名类型。它们在与局部变量一起使用时很好,但正如您所注意到的,当它们脱离方法的限制时,使用起来会变得非常麻烦。

更好的替代方法是元组:

void Main(string[] args)
{
    var letterFreq1 = CountLetters("aabbbc");  
    var letterFreq2 = CountLetters("aabbbc");  

    if (letterFreq1.SequenceEqual(letterFreq2))
        Console.WriteLine("Is anagram");
    else
        Console.WriteLine("Is not an anagram");
}

public static List<(char Letter, int Count)> CountLetters(string input)
    => input.ToCharArray()
        .GroupBy(x => x)
        .Select(x => (Letter: x.Key, Count : x.Count()))
        .OrderBy(x => x.Letter)
        .ToList();

一个更好的解决方案是为此创建一个命名类型,但同样,根据您的情况,这可能是也可能不是您的好解决方案。