Значение ключевого слова where в методе расширения - PullRequest
2 голосов
/ 28 декабря 2011

Я следил за сообщением о методах расширения из этого сообщения :

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();
 }

Оба возвращают идентичные списки.Большое спасибо за ясность в том, что происходит!

Ответы [ 4 ]

3 голосов
/ 28 декабря 2011

С msdn

Предложение where используется для указания ограничений на типы, которые могут использоваться в качестве аргументов для параметра типа, определенного в обобщенном объявлении.Например, вы можете объявить универсальный класс MyGenericClass, чтобы параметр типа T реализовывал интерфейс IComparable:

открытый класс MyGenericClass, где T: IComparable {}

1 голос
/ 28 декабря 2011

Я почти уверен, что вы не спрашиваете, что означает «где». Вы спрашиваете: «Какой смысл ставить это там?»

В исходном сообщении, на которое вы ссылались, Сэм Саффрон сказал: «Подобный вспомогательный класс может быть создан для сравнения объектов. (Для этого потребуется улучшить обработку нуля)». Итак, с вашим маленьким набором тестов все идет не так, потому что вы не пропускаете нули. Попробуйте передать нули, и он взорвется.

Вероятно, произошло то, что Сэм Саффрон написал EqualityComparer, а затем понял, что ему следует проверять наличие нулей повсюду, что делает его код непригодным в качестве примера, поэтому вместо добавления нулевых проверок он просто переименовывается это StructEqualityComparer, и он заставил его работать только со структурами.

1 голос
/ 28 декабря 2011

Я полагаю, что вы знаете, что такое ограничения универсального типа и особенно where : struct. Если коротко, указав такое ограничение, вы указываете, что в качестве параметра универсального типа можно использовать только типы значений, например int, double и т. Д..

В текущей реализации Distinct и StructEqualityComparer это действительно не имеет никакого значения, но идея StructEqualityComparer состоит в том, чтобы сравнивать структуры, название которых говорит об этом, поэтому все классы / методы, которые передаютсячерез собственные параметры универсального типа, требуемые для StructEqualityComparer, обязано переопределить те же ограничения универсального типа, что и.В вашем случае Distinct() метод passign свой собственный параметр T, поэтому обязан переопределить все ограничения.

1 голос
/ 28 декабря 2011

Ключевое слово where используется для определения универсального параметра.В этом случае вы указываете, что StructEqualityComparer должен принимать что-то, что является типом значения (или struct), так что сравнение на равенство будет сравниваться по значению, а не по ссылке.

...