关于函数的通用约束

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.

  • 您可以使用`object.Equals(a,b)`而不是`a.Equals(b)`,这样您就不必担心空对象了. (6认同)