可以从表达式参数

时间:2019-12-08 11:46:55

标签: c# generics types interface type-inference

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

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:这是完整的代码段。

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

1 个答案:

答案 0 :(得分:2)

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

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