我创建了一个验证器,用于检查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吗?它可以以某种方式推断出来吗?
答案 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);