C# 函数的一般约束
我想写一个对类型有约束的泛型函数。我特别想要这样的东西:C# 函数的一般约束,c#,generics,type-constraints,C#,Generics,Type Constraints,我想写一个对类型有约束的泛型函数。我特别想要这样的东西: bool IsInList<T>(T value, params T[] args) { bool found = false; foreach(var arg in args) { if(arg == value) { found = true; break; } } return foun
bool IsInList<T>(T value, params T[] args)
{
bool found = false;
foreach(var arg in args)
{
if(arg == value)
{
found = true;
break;
}
}
return found;
}
然而,编译器在相等线上发出嘎嘎声。所以我想对它实现的IEquatable类型加上一个约束。然而,约束似乎只在类级别起作用。这是正确的,还是有某种方法可以通用地指定它?通常,“==”运算符仅用于不可变类型—(内置值类型或自定义不可变类型重载了==运算符。除非重载它,否则如果在引用类型上使用它,(字符串除外)只有当两个变量都指向同一类型的实例(同一对象)时,它才会返回true。如果两个veriable都指向该类型的不同实例,即使它们都具有相同的内部数据值,它也会返回false 因此,您需要将类型T限制为那些实现
Equals()
函数的类型,该函数用于确定任何类型的两个实例是否“相等”,而不仅仅是它们都指向同一实例……并使用该函数。
内置接口IEquatable
为您表达了这一点。(有点像IComparable
要求类型具有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;
}
bool IsInList(T值,参数T[]args),其中T:IEquatable
{
foreach(args中的变量arg)
if(value.Equals(arg))返回true;
返回false;
}
您还应该理解Equals()和==之间的区别,并决定哪一个更适合您的意图……查看参考以了解更多信息。只需替换即可
arg == value
与
通用约束也适用于通用方法:
bool IsInList<T>(T value, params T[] args) where T : IEquatable<T>
bool IsInList(T值,参数T[]args),其中T:IEquatable
但是,IEquatable
没有定义运算符==
,只定义等于(t)
因此,您应该使用Equals()
,甚至不需要约束:Equals(object)
是object
的成员
另外,不要忘记,如果对象为
null
则Equals
将不起作用,其他人提到了IEquatable
,这当然是一个很好的潜在约束
另一个要记住的选项是EqualityComparer.Default
,如果可用,它将使用IEquatable
,但如果不可用,则返回到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;
}
包含
,因此您可以将代码简化为:
bool IsInList<T>(T value, params T[] args)
{
return args.Contains(value);
}
args
是一个数组,而不是列表,您的方法可能有点命名错误
这不起作用,
IEquatable
不包含运算符==
,它也不是以某种方式神奇地创建的。而且,Equals()
即使没有IEquatable
(尽管它是等于(对象)
而不是等于(t)
)。是的,但您不能期望编译器在您定义的任意自定义类型上为您实现Equals方法的代码。您必须自己编写该代码。此约束仅限制您在未实现此方法的类型上调用该方法。而且,是的,您的==运算符为否也是正确的在IEquatable中我的错误,我编辑了以更正…查看我添加的链接以了解更多信息。不,这不完全是同一件事。IEquatable.Equals
的签名与object.Equals
的签名不同。通过这种方式约束它,你阻止它在默认相等比较完美的类型上工作很好。很遗憾,基本上没有办法说“将T约束到具有自定义相等比较的类型”-您当前的约束太窄,“无约束”可以说太宽。+1是非常详细的答案,但我认为您的第一个代码中有一个错误:if(comparer.Equals(arg==value))-我认为应该是if(comparer.Equals(arg,value))。@ShdNx:Whoops,绝对:)不是IndexOf
只是System.Array
上的一个静态方法。你可以使用object.Equals(a,b)
而不是a.Equals(b)
,这样您就不必担心空对象。现在,如果MS能够更新他们的文档以反映这一现实,而不是给每个人留下约束仅对类声明有效的印象,那就好了。
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;
}
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;
}
bool IsInList<T>(T value, params T[] args)
{
return args.Contains(value);
}
bool IsInList<T>(T value, params T[] args)
{
return Array.IndexOf(args, value) != -1;
}