List<String>.Contains(mystring)是进行引用比较还是值比较?

4
List.Contains(mystring)是执行引用比较还是值比较? 例如,我有以下代码:
/// <summary>
/// If the value isn't null or an empty string, 
/// and doesn't exist in the list, it adds it to the list
/// </summary>
static void AddToListIfNotEmpty(List<string> thelist, SqlString val)
{
  string value = val.ToString().Trim();
  if (!string.IsNullOrEmpty(value))
  {
    bool found = false;
    foreach (string x in thelist) if (x == value) found = true;
    if (!found) thelist.Add(value);
  }
}

我可以简化foreach和下面的代码为:

if (!thelist.Contains(value)) thelist.Add(value);

谢谢

4个回答

7

IList<T>使用Comparator<T>.Default进行比较,而这又通过值比较String对象进行比较。

如果您愿意,您可以将项目移动到IDictionary<T, bool>或类似的地方,在那里可以指定您的IComparator - 指定检查引用的比较器。(即使在这种情况下,您最好使用foreach循环)

如果您可以使用LINQ,您也可以创建一个具有引用比较的语句。


按引用进行比较没有意义。SqlString 引用不可能等于已经在列表中的 string - Thorarin
你说得对,我没有注意到那一点。那样的话,使用IDictionary技巧或LINQ是他的选择。 - Aviad Ben Dov
等等,我有点困惑。他正在比较 ToString().Trim() 的值,而不是 SqlString 本身。Equals 可能有效,即使字符串被内部化,引用比较也可能有效。 - Aviad Ben Dov
字符串不会自动进行内部化,但是String类的等号操作符是按值比较而不是按引用比较的。如果要比较引用,您需要先将其转换为object - Thorarin
我知道。尽管如此,我的答案依然如初。 :) - Aviad Ben Dov
显示剩余2条评论

5

来自List<T>.ContainsMSDN

此方法使用默认的相等比较器EqualityComparer<T>.Default来确定相等性,其中T是列表中的值的类型。

... Default属性检查类型T是否实现了IEquatable<T>通用接口,如果是,则返回一个使用该实现的EqualityComparer<T>。否则,它将返回一个使用T提供的Object.EqualsObject.GetHashCode重写的EqualityComparer<T>

从反射器(和最小惊讶原则)来看,字符串相等具有值类型语义-因此,如果它们具有相同的字符串,则它们是相等的。 Equals(Object)IEquatable.Equals(T)都委托给String::EqualsHelper


4

所有字符串的比较都被重载为按值比较。抱歉,我没有注意到你有一个SqlString,为什么不使用它的ToString()方法并添加呢?你缩短的方法无法编译。


你说它编译不了是什么意思?它完全可以顺利编译。value 是将 val 转换为字符串后得到的结果。 - Thorarin

2
是的,您可以简化代码(而非复杂性*),通过移除foreach语句,但是您的简化方式并不与您原来的代码完全相同。
简化后的等效代码如下:
(以下文本可能需要上下文语境才能正确翻译,请酌情参考)
static void AddToListIfNotEmpty(List<string> thelist, SqlString val)
{
    string value = val.ToString().Trim();
    if (value != string.Empty && !thelist.Contains(value))
        thelist.Add(value);
}

请注意,您的string.IsNullOrEmpty()永远不会遇到字符串的null引用。编辑:检查后,我注意到SqlString.ToString()方法将空的SqlString转换为字面值"Null",这不是您想要的。您应该将此作为方法中的第一件事添加:
if (val.IsNull)
    return;

最后,回到我的复杂性评论:如果你正在处理大量元素,你可能想要考虑使用 HashSet 而不是使用 List(相同的命名空间)。它不会维护添加字符串的顺序,但它的 Contains 操作是 O(1),而你当前的操作是 O(n)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接