【问题标题】:C# Generic method that can infer its type argument from expression parameter可以从表达式参数推断其类型参数的 C# 通用方法
【发布时间】:2020-04-01 17:47:14
【问题描述】:

我正在尝试创建一个方法,它可以接受对象的类型作为类型参数,以及对对象属性之一及其类型的引用。像这样:

service.DoWork<DateTime>(dt => dt.Ticks).

我查看了其他库是如何做这些事情的,最终得到了以下定义:

interface IService
{
    void DoWork<TObject, TProperty>(Expression<Func<TObject, TProperty>> propertySelector);
}

理想情况下,用户可以传入对象的类型,然后使用表达式“选择”其每个属性。然后我的方法可以知道选择的表达式,以及它的类型对象的类型

  service.DoWork<DateTime>(dt => dt.Ticks);
  service.DoWork<DateTime>(dt => dt.TimeOfDay);
  service.DoWork<DateTime>(dt => dt.Second);

但是,以这种方式调用该方法会导致以下错误:

Using the generic method 'IService.DoWork<TObject, TProperty>(Expression<Func<TObject, TProperty>>)' requires 2 type arguments

如果我指定属性的类型,那么一切正常:

  service.DoWork<DateTime, long>(dt => dt.Ticks);
  service.DoWork<DateTime, TimeSpan>(dt => dt.TimeOfDay);
  service.DoWork<DateTime, int>(dt => dt.Second);

但是,这似乎真的是多余的。编译器可以从我提供的表达式参数中提取类型,据我所知,许多其他库都使用这种类型推断来提供干净的接口(Linq、MOQ、FluentAssertions 等等)

我想我需要以某种方式更改我的方法定义,但我似乎找不到正确的方法来做到这一点。

PS:这里是完整的代码sn-p。

using System;
using System.Linq.Expressions;

namespace GenericTypeInterface
{
    class Program
    {
        static void Main(string[] args)
        {
            IService service = null;

            service.DoWork<DateTime>(dt => dt.Ticks);
            service.DoWork<DateTime>(dt => dt.TimeOfDay);
            service.DoWork<DateTime>(dt => dt.Second);
        }
    }

    interface IService
    {
        void DoWork<TObject, TProperty>(Expression<Func<TObject, TProperty>> propertySelector);
    }
}

【问题讨论】:

  • 类型推断全部或全部无效,您不能指定一个参数而让编译器猜测所有其他参数。如果 DoWork 有两个参数,则指定两个参数或一个都不指定。

标签: c# generics types interface type-inference


【解决方案1】:

您可以通过显式编写 lambda 参数的类型让它“推断”两个通用参数:

service.DoWork((DateTime dt) => dt.Ticks);

【讨论】:

  • 很好,这行得通。但是,我真的希望找到一种不需要转换输入参数的方法。我真的很想保留service.DoWork&lt;DateTime&gt;(dt =&gt; dt.Ticks)
  • 没有别的办法,你在这里定义一个新变量,除了你,没有人知道它应该是一个DateTime。如果你使用 x 而不是 dt,也许你会更清楚。
  • @Kobek 根本不涉及选角。这只是简单地指定 lambda 表达式的参数类型,它是 lambda 表达式语法的一部分 - 为 lambda 表达式的参数指定类型是可选的。不可能按照您想要的方式进行操作,因为DoWork 有 2 个通用参数,您必须同时指定或不指定任何参数。您不能让编译器推断出 some 的泛型参数。也许这会是未来的一个功能,但不是现在。
  • 好的,谢谢。我会看看我是否可以重写我的界面以省略两个参数
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-06
  • 2011-04-07
相关资源
最近更新 更多