Jes*_*caB 10 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 found;
}
Run Code Online (Sandbox Code Playgroud)
关键是您可以检查项目是否在参数列表中:
if(IsInList("Eggs", "Cheese", "Eggs", "Ham"))
Run Code Online (Sandbox Code Playgroud)
但是,编译器在平等线上呱呱叫.所以我想对它实现IEquatable的类型进行约束.但是,限制似乎只在班级有效.这是正确的,还是有某种方法来指定这一点?
Jon*_*eet 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;
}
Run Code Online (Sandbox Code Playgroud)
请注意,默认的相等比较器也可以处理空引用,因此您不必自己担心这些问题.如果类型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;
}
Run Code Online (Sandbox Code Playgroud)LINQ已经包含了一个方法Contains,因此您可以将代码简化为:
bool IsInList<T>(T value, params T[] args)
{
return args.Contains(value);
}
Run Code Online (Sandbox Code Playgroud)Array有效地包含此功能,具有IndexOf:
bool IsInList<T>(T value, params T[] args)
{
return Array.IndexOf(args, value) != -1;
}
Run Code Online (Sandbox Code Playgroud)你的方法可能有点误导,因为它args是一个数组,而不是一个数组List<T>.
svi*_*ick 10
通用约束也适用于泛型方法:
bool IsInList<T>(T value, params T[] args) where T : IEquatable<T>
Run Code Online (Sandbox Code Playgroud)
但是,IEquatable<T>没有定义operator ==,只有Equals(T).
所以,你应该使用Equals(),你甚至不需要约束:Equals(object)是...的成员object.
另外不要忘记,Equals如果对象是无效的null.