我想编写一个对类型有约束的泛型函数。具体来说,我想要这样的东西:
bool IsInList<T>(T value, params T[] args)
{
bool found = false;
foreach(var arg in args)
{
if(arg == value)
{
found = true;
break;
}
}
return found;
}
关键是您可以检查项目是否在参数列表中:
if(IsInList("Eggs", "Cheese", "Eggs", "Ham"))
然而,编译器在平等线上呱呱叫。所以我想对它实现IEquatable的类型进行约束。但是,限制似乎只在班级有效。这是正确的,还是有某种方法来指定这一点?
答案 0 :(得分:11)
其他人提到IEquatable<T>
这肯定是一个很好的潜在约束。
要记住的另一个选项是EqualityComparer<T>.Default
,如果可用,将使用IEquatable<T>
,否则将回退到object.Equals(object)
。这意味着您可以将其用于先于泛型但覆盖Equals
的类型,例如:
bool IsInList<T>(T value, params T[] args)
{
IEqualityComparer<T> comparer = EqualityComparer<T>.Default;
bool found = false;
foreach(var arg in args)
{
if(comparer.Equals(arg, value))
{
found = true;
break;
}
}
return found;
}
请注意,默认的相等比较器也可以处理空引用,因此您无需担心这些问题。如果类型T
未覆盖object.Equals(object)
或已实现IEquatable<T>
,您将获得引用相等语义(即,如果确切引用位于数组中,它将仅返回true
)。
其他几点:
您希望坚持单一退出点,使代码的可读性降低,IMO。这里不需要额外的变量:
bool IsInList<T>(T value, params T[] args)
{
IEqualityComparer<T> comparer = EqualityComparer<T>.Default;
foreach (var arg in args)
{
if (comparer.Equals(arg, value))
{
return true;
}
}
return false;
}
LINQ已经包含了一个方法Contains
,因此您可以将代码简化为:
bool IsInList<T>(T value, params T[] args)
{
return args.Contains(value);
}
Array
也有效地包含此功能,IndexOf
:
bool IsInList<T>(T value, params T[] args)
{
return Array.IndexOf(args, value) != -1;
}
鉴于args
是一个数组,而不是List<T>
,您的方法可能会有一点误导性地命名。
答案 1 :(得分:9)
通用约束也适用于泛型方法:
bool IsInList<T>(T value, params T[] args) where T : IEquatable<T>
但是,IEquatable<T>
未定义operator ==
,仅定义Equals(T)
。
因此,您应该使用Equals()
,甚至不需要约束:Equals(object)
是object
的成员。
另请注意,如果对象为Equals
,null
将无效。
答案 2 :(得分:1)
`=='运算符通常仅用于不可变类型 - (内置值类型或重载==运算符的自定义不可变类型。除非你重载它,否则在引用类型上使用它,(除了如果两个变量都指向同一个类型的实例(同一个对象),它只返回true。如果两个变量指向该类型的不同实例,即使它们都具有所有相同的内部数据值,它也会返回false。 / p>
所以你需要将类型T限制为那些实现Equals()
函数的类型,这个函数用于确定任何类型的两个实例是否“相等”,而不仅仅是它们都指向同一个实例......而是用它来代替。
内置接口IEquatable<T>
为您表达了这一点。 (有点像IComparable<T>
要求类型具有CompareTo()
功能)
此外,您可以使您的功能更加简洁明了......
试试这个:
bool IsInList<T>(T value, params T[] args) where T:IEquatable<T>
{
foreach(var arg in args)
if(value.Equals(arg)) return true;
return false;
}
您还应该了解Equals()和==之间的区别,并确定哪个更适合您的意图...查看this参考了解更多信息。
答案 3 :(得分:0)
只需替换
arg == value
与
arg.Equals(value)