如果你在一个通用类中使用'RemoveAll',你打算用它来保存任何类型对象的集合,如下所示:
public class SomeClass<T>
{
internal List<T> InternalList;
public SomeClass() { InternalList = new List<T>(); }
public void RemoveAll(T theValue)
{
// this will work
InternalList.RemoveAll(x => x.Equals(theValue));
// the usual form of Lambda Predicate
// for RemoveAll will not compile
// error: Cannot apply operator '==' to operands of Type 'T' and 'T'
// InternalList.RemoveAll(x => x == theValue);
}
}
答案 0 :(得分:4)
因为T可以是值类型,所以你必须做这样的事情:
public class SomeClass<T> where T : class
{
internal List<T> InternalList;
public SomeClass() { InternalList = new List<T>(); }
public void RemoveAll(T theValue)
{
// this will work
InternalList.RemoveAll(x => x == theValue);
}
}
请注意,只是检查参考平等是你真正想要的。
更新:我最初忘记提及这一点,但这当然意味着您将无法将其用于价值类型。另一种方法是使用类似的东西来支持两者:
public abstract class SomeCollection<T>
{
internal List<T> InternalList;
public SomeCollection() { InternalList = new List<T>(); }
public abstract void RemoveAll(T theValue);
}
public class ReferenceCollection<T> : SomeCollection<T> where T : class
{
public override void RemoveAll(T theValue)
{
InternalList.RemoveAll(x => x == theValue);
}
}
public class ValueCollection<T> : SomeCollection<T> where T : struct
{
public override void RemoveAll(T theValue)
{
InternalList.RemoveAll(x => x.Equals(theValue));
}
}
答案 1 :(得分:2)
如果您想让代码尽可能灵活,可以像这样使用EqualityComparer<T>.Default
:
public void RemoveAll(T theValue)
{
// this will work
InternalList.RemoveAll(x => EqualityComparer<T>.Default.Equals(x, theValue));
}
该代码适用于任何类型的T(包括可空类型和值类型),它可以避免装箱,它还可以处理T实现IEquatable<T>
或覆盖object.Equals
的情况。来自documentation:
Default属性检查类型T是否实现了 System.IEquatable(T)接口,如果是,则返回一个 EqualityComparer(T)使用该实现。否则,它 返回使用覆盖的EqualityComparer(T) 由T。
提供的Object.Equals和Object.GetHashCode
答案 2 :(得分:0)
它必须适用于所有类型的T Reference和ValueTypes。
System.ValueType中Equals的默认实现具有以下内容(来自ms引用源)
// if there are no GC references in this object we can avoid reflection
// and do a fast memcmp
if (CanCompareBits(this))
return FastEqualsCheck(thisObj, obj);
FieldInfo[] thisFields = thisType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
for (int i=0; i<thisFields.Length; i++) {
thisResult = ((RtFieldInfo)thisFields[i]).InternalGetValue(thisObj,false);
thatResult = ((RtFieldInfo)thisFields[i]).InternalGetValue(obj, false);
if (thisResult == null) {
if (thatResult != null)
return false;
}
else
if (!thisResult.Equals(thatResult)) {
return false;
}
}
您应该考虑在值类型上实现Equals方法 因为System.ValueType上的默认实现不会 执行以及您的自定义实现。
所以我相信答案是设计人员不希望人们依赖于== for System.ValueTypes的隐式运算符,并希望他们在适用的情况下实现更好的版本。
答案 3 :(得分:0)
operator==
受编译器约束,并要求两个参数具有相同的编译时类型。
使用object.operator==
:
InternalList.RemoveAll(x => (object)x == (object)theValue);
或Equals
(可以覆盖并考虑运行时类型)
InternalList.RemoveAll(x => x.Equals(theValue));