按引用传递进行比较?

10
当使用System.Collections.Generic中的List类时,像Contains或IndexOf这样的方法将使用IEquatable实现的Equals方法或由Object类提供的覆盖的Equals方法来比较传递的引用对象。如果未覆盖Object.Equals,则它将检查传递的引用是否指向与自身相同的对象。
我的问题是:如果Equals被覆盖,是否有一种方法使List按引用进行比较? 下面的代码将从列表中删除该项:
class Program
{
    static void Main(string[] args)
    {    
        var s1 = new SomeClass() { A = 5 };
        var s2 = new SomeClass() { A = 5 };
        var list = new List<SomeClass>();
        list.Add(s1);
        list.Remove(s2); // s1 will get removed, even though s2 has been 
                         // passed, because s1's Equals method will return true.

    }
}

class SomeClass
{
    public int A { get; set; }

    public override bool Equals(object obj)
    {
        SomeClass s = obj as SomeClass;
        if (s == null)
        {
            return false;
        }
        else
        {
            return s.A == this.A;
        }
    }   
}

假设我无法移除 SomeClass 中的 Equals 实现,有没有一种方法可以使 List 按引用而非按值进行比较?

2个回答

14

你可以使用List.RemoveAll,并在谓词中使用Object.ReferenceEquals来比较项目。

list.RemoveAll(item => object.ReferenceEquals(item, s2));

在使用 Visual Studio 2010 Express 进行调试时,该代码成功地删除了1个项目。


4
奥斯汀的解决方案简单而有效。但是这里也有两个通用的扩展方法:
items.RemoveAllByReference(item);

public static void RemoveAllByReference<T>(this List<T> list, T item)
{
    list.RemoveAll(x=> object.ReferenceEquals(x, item));
}

public static bool RemoveFirstByReference<T>(this List<T> list, T item)
{
    var index = -1;
    for(int i = 0; i< list.Count; i++)
        if(object.ReferenceEquals(list[i], item))
        {
            index = i;
            break;
        }
    if(index == -1)
        return false;

    list.RemoveAt(index);
    return true;
}

有趣,但为什么这更优化 - 这不是类似于谓词在内部执行的吗?只是想知道你的推理... - Russ Clarke
如果项目在列表中出现了n次,会怎么样? - Austin Salonen
奥斯汀的方法总是检查所有元素。这个方法在找到一个元素后就会跳出循环。但现在我想,可能更正确的做法是搜索整个列表并删除列表中所有相同项...所以这取决于你想要什么。但是,如果您在多个地方使用它,则扩展方法是一种优势。 - doblak
@Austin,是的,你说得对,名字误导了,我修改了名称。现在这两个扩展方法做到了其所描述的功能。 - doblak

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