【问题标题】:Meaning of the where clause keyword in extension method扩展方法中where子句关键字的含义
【发布时间】:2011-12-28 23:56:31
【问题描述】:

我一直在关注来自 post 的关于扩展方法的帖子:

public static IEnumerable<T> Distinct<T,TKey>(this IEnumerable<T> list, Func<T,TKey> lookup) where TKey : struct {
        return list.Distinct(new StructEqualityComparer<T, TKey>(lookup));
    }

class StructEqualityComparer<T,TKey> : IEqualityComparer<T> where TKey : struct {

    Func<T, TKey> lookup;

    public StructEqualityComparer(Func<T, TKey> lookup) {
        this.lookup = lookup;
    }

    public bool Equals(T x, T y) {
        return lookup(x).Equals(lookup(y));
    }

    public int GetHashCode(T obj) {
        return lookup(obj).GetHashCode();
    }
}

有人可以解释附加到扩展方法和比较器类的where TKey : struct 的用途吗?删除这些语句似乎对简单的测试代码没有影响 - 两个评估 TKey 分别是类和结构的 int 类型:

public struct TestMeStruct
{
    public int a;
    public int b;
}

public class TestMeClass
{
    public int a { get; set; }
    public int b { get; set; }

}

public void Test()
{

        List<TestMeStruct> lstruct = new List<TestMeStruct>();

        lstruct.Add(new TestMeStruct() { a = 1, b = 2 });
        lstruct.Add(new TestMeStruct() { a = 3, b = 7 });
        lstruct.Add(new TestMeStruct() { a = 3, b = 14 });
        lstruct.Add(new TestMeStruct() { a = 32, b = 11 });


        List<TestMeClass> lclass = new List<TestMeClass>();
        lclass.Add(new TestMeClass() { a = 1, b = 2 });
        lclass.Add(new TestMeClass() { a = 3, b = 7 });
        lclass.Add(new TestMeClass() { a = 3, b = 14 });
        lclass.Add(new TestMeClass() { a = 32, b = 11 });

        var one = lstruct.Distinct(mem => mem.a).ToList();
        var two = lclass.Distinct(mem => mem.a).ToList();
 }

两者都返回相同的列表。非常有义务弄清楚发生了什么!

【问题讨论】:

    标签: c# .net generics where-clause


    【解决方案1】:

    来自msdn

    where 子句用于指定对可以执行的类型的约束 用作泛型中定义的类型参数的参数 宣言。例如,您可以声明一个泛型类, MyGenericClass,使得类型参数 T 实现 IComparable 接口:

    公共类 MyGenericClass where T:IComparable { }

    【讨论】:

    • +1 - 如果您关闭where,则允许传递除结构之外的其他类型。约束只是限制了这一点。
    【解决方案2】:

    我相信您知道什么是泛型类型约束,尤其是where : struct,简而言之 - 通过指定此类约束,您表明只有值类型可以用作泛型类型参数,例如intdouble 等.

    DistinctStructEqualityComparer 的当前实现中,这确实没有任何区别,但StructEqualityComparer 的想法是比较结构,它的名字就是这样,所以所有通过自己的泛型类型的类/方法StructEqualityComparer obligated 所需的参数也重新定义了相同的泛型类型约束。在您的情况下,Distinct() 方法传递了它自己的 T 参数,因此有义务重新定义所有约束。

    【讨论】:

    • 太棒了,完全有道理 - 也解释了为什么它接受 TKey 作为 int。非常感谢你们。
    【解决方案3】:

    where 关键字用于限定泛型参数。在这种情况下,您表明StructEqualityComparer 必须采用值类型(或struct),以便相等比较将按值而不是按引用进行比较。

    【讨论】:

      【解决方案4】:

      我很确定您不会问“在哪里”是什么意思。你在问'把它放在那里有什么意义'。

      在您链接到的原始帖子中,Sam Saffron 说“可以构建一个类似的辅助类来比较对象。(它需要更好地处理空值)”。所以,你的小测试套件没有任何问题,因为你没有传递任何空值。尝试传递空值,它会爆炸。

      可能发生的事情是 Sam Saffron 编写了一个 EqualityComparer,然后意识到他应该在所有地方检查空值,这会使他的代码有点不适合作为示例,所以他没有添加空值检查,而是重命名它到 StructEqualityComparer 并且他使它只适用于结构。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-04-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多