为何修改数组元素后,List的Contains()仍判定该数组存在?
为什么List<int[]>和List调用Contains()的判定结果不同?
我编写了两段C#代码:第一段创建List<int[]>集合three_number_sums,将数组_3Ints_arr添加到集合后修改其元素值,使用Contains()判定时仍认为该数组存在;第二段创建List<string>集合words,将字符串word添加后重新赋值为新字符串,Contains()则判定新字符串不存在。想知道这两种情况判定结果不同的原因。
第一段代码(数组示例)
List<int[]> three_number_sums = new List<int[]>(); int[] _3Ints_arr = { 2, 6, 9 }; three_number_sums.Add(_3Ints_arr); // 将数组存入List,此时数组元素为2,6,9 _3Ints_arr[0] = 1; _3Ints_arr[1] = 10; _3Ints_arr[2] = 100; // 数组元素变为1,10,100 if(!three_number_sums.Contains(_3Ints_arr)) // 判定结果为存在,不会执行Add three_number_sums.Add(_3Ints_arr);
第二段代码(字符串示例)
List<string> words = new List<string>(); string word = "apple"; words.Add(word); // 将字符串存入List,此时内容为"apple" word = "orange"; // 字符串变量指向新内容"orange" if (!words.Contains(word)) // 判定结果为不存在,执行Add words.Add(word);
核心原因解析
List<T>.Contains() 默认使用EqualityComparer<T>.Default实现相等性判断,不同类型的比较逻辑本质差异导致了结果不同:
1. 数组(int[])的判定逻辑
数组是普通引用类型,默认的相等性比较是引用相等——即判断两个变量是否指向内存中的同一个对象实例:
- 当你把
_3Ints_arr添加到List时,List存储的是该数组对象的内存引用地址。 - 修改数组元素的操作(如
_3Ints_arr[0] = 1)只是改变了这个引用指向的数组对象内部的内容,引用本身没有发生变化(仍然指向同一块内存)。 - 调用
Contains(_3Ints_arr)时,List会遍历内部元素,对比每个元素的引用是否和传入的_3Ints_arr一致,结果自然是一致的,因此返回true,不会执行后续的Add操作。
2. 字符串(string)的判定逻辑
字符串是不可变的引用类型,它的特殊性导致了行为差异:
- 初始时
word = "apple",变量word指向内存中存储"apple"的字符串对象,添加到List后,List存储的是这个"apple"对象的引用。 - 执行
word = "orange"时,由于字符串不可变,不会修改原来的"apple"对象内容,而是在内存中创建一个全新的"orange"字符串对象,并让变量word指向这个新的内存地址。 - 调用
Contains(word)时,传入的是"orange"对象的引用,而List中只有"apple"对象的引用,两者指向不同的内存对象,因此返回false,执行后续的Add操作。
扩展:如何让数组的Contains比较元素内容?
如果需要让List<int[]>.Contains()比较数组的元素内容而非引用,可以自定义相等比较器:
public class ArrayEqualityComparer<T> : IEqualityComparer<T[]> { public bool Equals(T[] x, T[] y) { if (x == null && y == null) return true; if (x == null || y == null) return false; if (x.Length != y.Length) return false; for (int i = 0; i < x.Length; i++) { if (!EqualityComparer<T>.Default.Equals(x[i], y[i])) return false; } return true; } public int GetHashCode(T[] obj) { if (obj == null) return 0; int hash = 17; foreach (var item in obj) { hash = hash * 31 + (item == null ? 0 : item.GetHashCode()); } return hash; } } // 使用方式 if (!three_number_sums.Contains(_3Ints_arr, new ArrayEqualityComparer<int>())) three_number_sums.Add(_3Ints_arr);
内容的提问来源于stack exchange,提问作者der chuan
相关产品推荐
相关产品推荐

