C# 奇怪的行为:将对象添加到ObservaleCollection
在将对象添加到ObservableCollection并查找它时,我有一种奇怪的行为。在添加之后,它被发现了,然后使用相同的代码,它就不再是了C# 奇怪的行为:将对象添加到ObservaleCollection,c#,.net,C#,.net,在将对象添加到ObservableCollection并查找它时,我有一种奇怪的行为。在添加之后,它被发现了,然后使用相同的代码,它就不再是了 public class TestClass { public TestClass(string s) { Str = s; } public string Str { get; set; } } private ObservableCollection<T
public class TestClass {
public TestClass(string s) {
Str = s;
}
public string Str {
get;
set;
}
}
private ObservableCollection<TestClass> testCollection = new ObservableCollection<TestClass>();
private List<string> newValueList = new List<string> { "one", "two", "three" };
private void Test() {
var tmpList = newValueList.Select(p => new TestClass(p));
foreach (var v in tmpList) {
testCollection.Add(v);
if (testCollection.Contains(v))
Console.WriteLine("YES");
else
Console.WriteLine("NO");
}
foreach (var v in tmpList) {
if (testCollection.Contains(v))
Console.WriteLine("IN");
else
Console.WriteLine("OUT");
}
}
公共类TestClass{
公共测试类(字符串s){
Str=s;
}
公共字符串Str{
得到;
设置
}
}
私有ObservableCollection testCollection=新ObservableCollection();
私有列表newValueList=新列表{“一”、“二”、“三”};
专用无效测试(){
var tmpList=newValueList.Select(p=>newtestclass(p));
foreach(tmpList中的var v){
testCollection.Add(v);
if(testCollection.Contains(v))
控制台。WriteLine(“是”);
其他的
控制台。写入线(“否”);
}
foreach(tmpList中的var v){
if(testCollection.Contains(v))
控制台。写入线(“IN”);
其他的
控制台。写入线(“输出”);
}
}
运行此代码将导致输出:YES OUT
当使用
.ToList()
到tmpList
时,您将得到预期的结果。您定义了一个运行时不知道如何比较它们的类。因此,当它们具有相同的引用而不是相同的Str
时,它假设它们中的两个相等。换句话说,当a
和b
是相同的地址时,TestClass
的两个对象(a
,b
)是相等的。如果要更改此设置并使a
和b
在具有相同的Str
时相等,则应覆盖Equals
和GetHashCode
。或
第一部分:
foreach (var v in tmpList) {
testCollection.Add(v);
if (testCollection.Contains(v))
Console.WriteLine("YES");
else
Console.WriteLine("NO");
}
在这里,您正在将v
添加到集合中,并检查v
是否在其中,因此它将返回“YES”
第二部分
foreach (var v in tmpList) {
if (testCollection.Contains(v))
Console.WriteLine("IN");
else
Console.WriteLine("OUT");
}
在这里,您要在集合中查找v(它不是对集合中对象的完全相同的引用(因为每次延迟求值都会在foreach迭代中生成新实例)),因此它将返回“OUT” 问题在于
tmpList
不是一个列表,而是一个“惰性”迭代器,它将在每次foreach
创建新对象时创建它
请更正行:
var tmpList = newValueList.Select(p => new TestClass(p)).ToList();
Select方法返回一个IEnumerable对象,该对象在循环中使用GetEnumerator时调用GetEnumerator,因此分别为两个循环调用列表中每个元素的Lambda in Select方法 Loop1:Select(p=>newtestclass(p)) Loop2:Select(p=>newtestclass(p)) 所以每当循环使用tmpList时 对于这两个循环,执行select语句,该语句调用lambda 因此,为每个循环创建不同的对象集 可以通过在lambda表达式中创建断点来验证此行为
您将看到它被调用了6次,而不是3次。对于此类比较,您应该在TestClass中实现Equals和GetHashCode。没有它,你只是比较参考。顺便说一句,这种行为与ObservaleCollection无关,它与LINQ到对象的Select方法的实现有关。谢谢,我认为这是真正发生的最好的解释。我认为值得明确指出的是,
tmpList
是惰性计算的,所以每次迭代它都会创建TestClass
的新实例,这就是引用等式失败的原因。如果将ToList()
添加到tmpList
行中,它将开始按预期打印“OUT”。我还认为真正的问题是惰性迭代器创建新对象。我不是比较变量(v)的地址,而是比较它们指向的地址(对象的地址)。否则,这样的代码将导致false,但结果为true:var a=v;var b=v;返回a==b;此外,使用.ToList()与使用相同比较时的预期效果相同。如果我错了,请纠正我。