Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 奇怪的行为:将对象添加到ObservaleCollection_C#_.net - Fatal编程技术网

C# 奇怪的行为:将对象添加到ObservaleCollection

C# 奇怪的行为:将对象添加到ObservaleCollection,c#,.net,C#,.net,在将对象添加到ObservableCollection并查找它时,我有一种奇怪的行为。在添加之后,它被发现了,然后使用相同的代码,它就不再是了 public class TestClass { public TestClass(string s) { Str = s; } public string Str { get; set; } } private ObservableCollection<T

在将对象添加到ObservableCollection并查找它时,我有一种奇怪的行为。在添加之后,它被发现了,然后使用相同的代码,它就不再是了

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()与使用相同比较时的预期效果相同。如果我错了,请纠正我。