【问题标题】:Can TKey be inferred? [duplicate]可以推断出 TKey 吗? [复制]
【发布时间】:2023-03-19 05:58:01
【问题描述】:

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

【问题讨论】:

  • 首先,您的代码甚至无法编译,没有无参数构造函数,IsValid 不采用 lambda。
  • 我不完全同意这个问题的“标记为重复”。另一篇文章询问 why 类型推断在构造函数中是不可能的。这个问题是如果有另一种方式。工厂方法有哪些(实际上在其他帖子的问题中提到了)
  • 所以,记录一下 :) 通过使用扩展方法:public static class SomeStaticClass { public static Validator&lt;T,TKey&gt; GetValidator&lt;T,TKey&gt;(this IEnumerable&lt;T&gt; list, Func&lt;T,TKey&gt; keyselector) { return new Validator&lt;T,TKey&gt;(keyselector); } } 您可以简单地使用:var list = new List&lt;Foo&gt;(); //Foo has a property named Bar of type string var validator = list.GetValidator(x =&gt; x.Bar); //compiler knows T (Foo) from the list and TKey from the returned property
  • 重新开放让我很难过。 duplicate I chose 很好地解释了为什么这是不可能的,并且该问题本身已经提供了一种解决方法:使用静态工厂方法,因为它适用于方法。 “我已经输入了答案”不是重新打开的理由。请作为 Generic Type in constructor 的副本再次关闭。
  • @CodeCaster 回想起来,我同意你的看法。我被 cmets 中的这种代码模糊分心了,因此决定重新打开,以便至少获得一个更好的 that 版本。

标签: c# linq generics lambda


【解决方案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);

【讨论】:

  • Pros to Me.Name 谁更快,答案几乎完全相同。
【解决方案2】:

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

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 

【讨论】:

    【解决方案3】:

    您可以使用临时对象将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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-17
      • 1970-01-01
      • 2022-01-17
      • 1970-01-01
      • 1970-01-01
      • 2018-04-25
      • 2021-05-28
      相关资源
      最近更新 更多