在字典中找不到c#对象

本文关键字:找不到 对象 字典 | 更新日期: 2023-09-27 18:13:16

我有一本字典。我使用下面的代码来获取对象的索引:

type.Name = _shuffledClasses.Where(entry => entry.Key.Name.Equals(originName))
                            .Where(entry => entry.Key.Namespace.Equals(type.Namespace))
                            .Select(item => item.Value).GetEnumerator().Current.Name;

但是它没有找到对象。我仔细检查了对象是否正确创建,是否存在,它确实存在!有问题的对象在"键"列中,我不想在"值"列中获得对象。

我也试过这段代码,它不能很好地工作:

type.Name = _shuffledClasses[new Classes()
{
     Name = originName,
     Namespace = type.Namespace
}].Name;

我的"Classes"对象如下所示:

class Classes
{
    public string Namespace { get; set; }
    public string Name { get; set; }
}

为什么找不到对象?

我做了一些研究,我尝试重写Equals和GetHashCode,现在我的类看起来像这样,仍然不工作:

public override bool Equals(object obj)
{
    Classes fooItem = obj as Classes;
    return fooItem == this;
}
public override int GetHashCode()
{
    return base.GetHashCode();
}

在字典<T, >中找不到c#对象

你的代码从根本上就被破坏了:

.GetEnumerator().Current.Name;

枚举数需要向前移动一个元素,MoveNext()Current将没有任何值。

同样,枚举数也应该被销毁。试试这个:

type.Name = _shuffledClasses.Where(entry => entry.Key.Name.Equals(originName))
                            .Where(entry => entry.Key.Namespace.Equals(type.Namespace))
                            .Select(item => item.Value)
                            .First().Name;

如果你出于任何原因不想使用First(),你也可以像这样手动迭代:

using (var enumerator = _shuffledClasses.Where(entry => entry.Key.Name.Equals(originName))
                            .Where(entry => entry.Key.Namespace.Equals(type.Namespace))
                            .Select(item => item.Value).GetEnumerator()) {
    enumerator.MoveNext(); // maybe check here if the operation is successful!
    type.Name = enumerator.Current.Name;
}

为什么找不到对象?

因为你没有在你的类中重写GetHashCode和Equals,这是它在Dictionary和HashSet中作为键所需的

Dictionary<TKey, TValue>需要一个相等的实现来确定键是否相等。您可以通过使用接受比较器参数的构造函数来指定IEqualityComparer<T>泛型接口的实现;如果不指定实现,则使用默认的泛型相等比较器EqualityComparer<T>.Default 。如果类型TKey实现了System.IEquatable<T>的泛型接口,则默认的相等比较器使用该实现。

如果你的类型没有实现IEquatable<T>,这个泛型比较器使用引用相等。

如果你不想实现你的自定义相等,你可以尝试使用LINQ和First,但这会破坏使用Dictionary<TKey, TValue>的目的,因为你将不得不扫描整个集合来获得该值:

shuffledClasses.First(x => x.Key.Name == myName && x.Key.Value == myValue).Value

如果你使用的是Dictionary,找到Key的最清晰的方法是使用[]TryGetValue

使用linq是伟大的,但在我看来,这不是一个地方使用它。在字典中搜索keyo(1)操作,但使用linq的方式将其转换为o(n)。如果您可以覆盖GetHashCodeEquals或提供自定义IEquatable<>,我认为这是更好的。

static void Main(string[] args)
{
    Dictionary<Classes, string> data = new Dictionary<Classes, string>
    {
        [new Classes { Name = "a", Namespace = "a" }] = "first",
        [new Classes { Name = "b", Namespace = "b" }] = "second",
    };
    var key = new Classes { Name = "a", Namespace = "a" };
    string result1 = data[key]; // "first"

    string result2;
    if (data.TryGetValue(key, out result2))
    {
        Console.WriteLine(result2); // 'first"
    }
}
class Classes
{
    public string Name { get; set; }
    public string Namespace { get; set; }
    public override bool Equals(object obj)
    {
        var other = obj as Classes;
        if (other == null)
            return false;
        return other.Name == Name &&
               other.Namespace == Namespace;
    }
    public override int GetHashCode()
    {
        return Name.GetHashCode() ^
               Namespace.GetHashCode();
    }
}

方法重写实现的问题是:

  1. = -在强制转换之后,您仍然没有实际比较属性

    public override bool Equals(object obj)
    {
        Classes fooItem = obj as Classes;
        return fooItem == this;
    }
    
  2. GetHashCode -你没有给它实现…仍然使用objectGetHashCode

    public override int GetHashCode()
    {
        return base.GetHashCode();
    }
    

更多参考参见:

  1. MSDN -实现Equals方法
  2. Stackoverflow -重写Equals()和GetHashCode()的正确方法
  3. Stackoverflow -为什么重要的是重写GetHashCode当Equals方法被重写?