使用列表<;customObject>;作为字典键c#
我有一本字典,它的关键是一个列表,如下所示使用列表<;customObject>;作为字典键c#,c#,c#-4.0,C#,C# 4.0,我有一本字典,它的关键是一个列表,如下所示 var dict = new Dictionary<List<MyKey>, Emp>(new MyCustomComparer()); 比较器类 public class MyCustomComparer : IEqualityComparer<List<MyKey>> { public bool Equals(List<MyKey> x, List<MyKey> y)
var dict = new Dictionary<List<MyKey>, Emp>(new MyCustomComparer());
比较器类
public class MyCustomComparer : IEqualityComparer<List<MyKey>>
{
public bool Equals(List<MyKey> x, List<MyKey> y)
{
return x.SequenceEqual(y);
}
public int GetHashCode(List<MyKey> obj)
{
return string.Join(",", obj.Select(s => s.Name)).GetHashCode();
}
}
public class MyCustomComparer : IEqualityComparer<IEnumerable<MyKey>>
{
public bool Equals(IEnumerable<MyKey> x, IEnumerable<MyKey> y)
{
return x.SequenceEqual(y);
}
public int GetHashCode(IEnumerable<MyKey> obj)
{
return string.Join(",", obj.Select(s => s.Name)).GetHashCode();
}
}
公共类MyCustomComparer:IEqualityComparer
{
公共布尔等于(列表x、列表y)
{
返回x.x(y);
}
public int GetHashCode(列表对象)
{
返回string.Join(“,”,obj.Select(s=>s.Name)).GetHashCode();
}
}
任何帮助都将不胜感激
关于发布更改的代码
var dict = new Dictionary<List<MyKey>, Emp>(new MyCustomComparer());
var key1 = new List<MyKey>
{
{new MyKey{ Name = "string1"}}
};
dict.Add(key1, new Emp());
var key2 = new List<MyKey>
{
{new MyKey{ Name = "string1"}}
};
if (!dict.ContainsKey(key2))
{
dict.Add(key2, new Emp());
}
public class MyKey
{
public string Name { get; set; }
public override int GetHashCode()
{
return Name.GetHashCode();
}
public override bool Equals(object obj)
{
var myKey = obj as MyKey;
if (myKey != null)
{
return Name == myKey.Name;
}
return false;
}
}
public class Emp
{
}
var dict=newdictionary(new MyCustomComparer());
var key1=新列表
{
{new MyKey{Name=“string1”}
};
dict.Add(键1,新Emp());
var key2=新列表
{
{new MyKey{Name=“string1”}
};
如果(!dict.ContainsKey(键2))
{
dict.Add(键2,新Emp());
}
公共类MyKey
{
公共字符串名称{get;set;}
公共覆盖int GetHashCode()
{
返回Name.GetHashCode();
}
公共覆盖布尔等于(对象对象对象)
{
var myKey=obj作为myKey;
如果(myKey!=null)
{
返回Name==myKey.Name;
}
返回false;
}
}
公共级电磁脉冲
{
}
比较器类
public class MyCustomComparer : IEqualityComparer<List<MyKey>>
{
public bool Equals(List<MyKey> x, List<MyKey> y)
{
return x.SequenceEqual(y);
}
public int GetHashCode(List<MyKey> obj)
{
return string.Join(",", obj.Select(s => s.Name)).GetHashCode();
}
}
public class MyCustomComparer : IEqualityComparer<IEnumerable<MyKey>>
{
public bool Equals(IEnumerable<MyKey> x, IEnumerable<MyKey> y)
{
return x.SequenceEqual(y);
}
public int GetHashCode(IEnumerable<MyKey> obj)
{
return string.Join(",", obj.Select(s => s.Name)).GetHashCode();
}
}
公共类MyCustomComparer:IEqualityComparer
{
公共布尔等于(IEnumerable x,IEnumerable y)
{
返回x.x(y);
}
public int GetHashCode(IEnumerable obj)
{
返回string.Join(“,”,obj.Select(s=>s.Name)).GetHashCode();
}
}
另一种方法:
public class MyCustomKey : ReadOnlyCollection<MyKey>
{
public override int GetHashCode()
{
return this.Aggregate(0, (c, i) => c + i.Name.GetHashCode()*i.Name.Length);
}
public override bool Equals(object obj)
{
var myKey = obj as MyCustomKey;
if (myKey!= null && myKey.Count == this.Count)
{
return myKey.Zip(this, (i, j) => i.Name == j.Name).All(i=>i);
}
return false;
}
}
var dict = new Dictionary<MyCustomKey, Emp>();
var key1 = new MyCustomKey(new[] {new MyKey {Name = "string1"}});
dict.Add(key1, new Emp());
var key2 = new MyCustomKey(new[] {new MyKey {Name = "string1"}});
if (!dict.ContainsKey(key2))
{
dict.Add(key2, new Emp());
}
公共类MyCustomKey:ReadOnlyCollection
{
公共覆盖int GetHashCode()
{
返回此.Aggregate(0,(c,i)=>c+i.Name.GetHashCode()*i.Name.Length);
}
公共覆盖布尔等于(对象对象对象)
{
var myKey=obj作为MyCustomKey;
if(myKey!=null&&myKey.Count==this.Count)
{
返回myKey.Zip(this,(i,j)=>i.Name==j.Name).All(i=>i);
}
返回false;
}
}
var dict=新字典();
var key1=new MyCustomKey(new[]{new MyKey{Name=“string1”});
dict.Add(键1,新Emp());
var key2=new MyCustomKey(new[]{new MyKey{Name=“string1”});
如果(!dict.ContainsKey(键2))
{
dict.Add(键2,新Emp());
}
在MyKey
类中没有GetHashCode
和Equals
实现,因此SequenceEqual
中的比较将比较引用,而不是Name
属性的值。您的GetHashCode()
也是一个问题,它获取返回的IEnumerable
的哈希代码。但你更大的问题是,如果你改变其中一个列表,而它正在执行滚动作为一个关键,它会打破字典。字典不能处理在执行键滚动时发生变化的对象。@PrestonGuillot:这将是关于在键类型中使用Equals
和GetHashCode
,但是的,这就是它的本质。除了@ScottChamberlain之外,你至少应该使用ReadOnlyCollection
而不是List
。将可变结构作为字典键可能会让你头疼。。。其次,MyCustomComparer
的GetHashCode
正在返回IEnumerable
的哈希代码,而不是从Name属性返回。我想你忘了连接字符串了?而且,即使你使用一个不可变的列表,并在MyKey
上实现GetHashCode
和Equals
来依赖MyKey.Name
,你仍然会遇到一个问题,MyKey.Name
是可变的-如果用作键的列表中该属性的值发生变化,然后字典就会坏了。一般提示:不要将可变对象用作字典的键。虽然这确实解决了您的直接问题,但如果在将列表添加到字典后对其进行修改,则会遇到问题。要查看此操作,请将key1
设置为空列表,然后调用dict.Add(key1,new Emp())
然后执行key1.Add(new MyKey{Name=“string1”})
然后不经修改地运行程序的其余部分。如果任何名称中有逗号,则比较器很容易被破坏。您不应该将字符串压缩在一起,而应该将每个字符串的哈希值组合在一起。@Servy我同意他不应该将字符串组合在一起,但名称中的逗号不会打断它。事实上,他也可以轻松地执行string.Join(“,obj.Select(s=>s.Name))
字符串从不被“查看”,它只被用作生成哈希代码的不透明块。@ScottChamberlain在这种情况下,他的等于
检查已正确完成,因此是的,这只会增加他的冲突率,而不是导致不正确的行为。我习惯于看到人们在这两个地方使用相同的模式,导致可能的误报。@ScottChamberlain您的建议是什么?@PrestonGuillot事实上,这个问题的公认答案是,现在是从列表继承的最佳时机。海报所做的只是扩展列表的行为,以支持生成哈希代码,并等于使用列表中的成员。列表仍然只表示一个列表,它只是修改了相等行为。@ScottChamberlain我认为键必须/应该是不可变的,因为列表不是,所以类实际上并不表示列表。我想买ReadOnlyCollection。谢谢,我已经编辑了我的答案,使之成为不可变键