可以推断TKey吗?

时间:2016-12-23 12:13:14

标签: c# linq generics lambda

我创建了一个验证器,用于检查IList<T>是否有重复项。我想出了以下实现:

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var bar = new Foo() {Bar = "buzz"};
            var list = new List<Foo>() { }; //Foo has a property named Bar of type string
            var validator = new Validator<Foo, string>(x => x.Bar); //I have to specify the type of Bar
            validator.IsValid(list);
        }
    }
}

public class Foo
{
    public string Bar { get; set; }
}

public class Validator<T, Tkey>
{
    private readonly Func<T, Tkey> _keySelector;

    public Validator(Func<T, Tkey> keySelector)
    {
        _keySelector = keySelector;
    }

    public bool IsValid(IList<T> list)
    {
        if (list != null && list.Count > 0)
        {
            if (list.GroupBy(_keySelector).Any(g => g.Count() > 1))
            {
                return false;
            }
        }

        return true;
    }
}

但我不喜欢它必须如何使用:我必须在施工期间指定Bar的类型。

问题是我可以在初始化Validator时以某种方式跳过TKey吗?它可以以某种方式推断出来吗?

3 个答案:

答案 0 :(得分:1)

您可以使用扩展(工厂)方法来创建验证器。编译器将知道如何解析类型:

public static class SomeStaticClass
{
    public static Validator<T,TKey> CreateValidator<T,TKey>(this IEnumerable<T> list, Func<T,TKey> keyselector)
    {
        return new Validator<T,TKey>(keyselector);
    }
}

现在可以使用以下命令创建验证器:

var list = new List<Foo>(); //Foo has a property named Bar of type string
var validator = list.CreateValidator(x => x.Bar); //the compiler can infer T (Foo) through the list and TKey from the returned property inside the lambda 

答案 1 :(得分:1)

您可以使用通用扩展方法,该方法需要单独的静态类。通用方法可以从它们的参数中导出T类型。

以下是:

public static class Extensions
{
    public static Validator<T, TKey> GetValidatorFor<T, TKey>(this List<T> list, Func<T, TKey> getter) where T : class
    {
        return new Validator<T, TKey>(getter);
    }
}

然后你可以像这样使用它:

var list = new List<Foo>();
var validator = list.GetValidatorFor(x => x.Bar);

答案 2 :(得分:0)

您可以使用临时对象将currying应用于通用参数:

static class Validator
{
    public static ValidatorConstructor<T> Construct<T>() => new ValidatorConstructor<T>();
}

class ValidatorConstructor<T>
{
    public Validator<T, TKey> WithSelector<TKey>(Func<T, TKey> selector) => new Validator<T, TKey>(selector);
}

class Validator<T, TKey>
{
    public Validator(Func<T, TKey> selector)
    {
    }
}

用法:

Validator<Foo, Bar> e = Validator.Construct<Foo>().WithSelector(x => x.Bar);