C# 从lambda/代码解释返回匿名类型

C# 从lambda/代码解释返回匿名类型,c#,lambda,reflection,C#,Lambda,Reflection,此代码来自stackoverflow的Lukazoid先生。我想知道这是怎么回事。对我来说,你怎么称呼这样的方法有点奇怪。TResult的角色是什么 public static string[] Foo<T, TResult>(Expression<Func<T, TResult>> func) { return typeof(TResult).GetProperties().Select(pi => pi.Name).ToArray(); }

此代码来自stackoverflow的Lukazoid先生。我想知道这是怎么回事。对我来说,你怎么称呼这样的方法有点奇怪。
TResult
的角色是什么

public static string[] Foo<T, TResult>(Expression<Func<T, TResult>> func)
{
    return typeof(TResult).GetProperties().Select(pi => pi.Name).ToArray();
}

Foo((Person x) => new { x.LastName, x.DateOfBirth });
公共静态字符串[]Foo(表达式func)
{
返回typeof(TResult).GetProperties().Select(pi=>pi.Name).ToArray();
}
Foo((Person x)=>new{x.LastName,x.DateOfBirth});
非常感谢。

Func
表示声明如下的函数:

TResult functionName(T参数)

换句话说,
TResult
是函数返回的值的类型。前面的类型(
T
在本例中)是传递给函数的参数类型

在这段代码中,
Foo((personx)=>new{x.LastName,x.DateOfBirth})
,正在向方法
Foo
传递一个带有签名的匿名方法
Func

换句话说,
TResult
包含姓名和出生的匿名类型

由于
Foo
方法需要一个
表达式
,因此在传递给Foo之前,该匿名方法实际上会转换为一个表达式,但这是另一个讨论的故事

您提供的代码返回
string[]{“LastName”,“DateOfBirth”}
Func
表示一个声明如下的函数:

TResult functionName(T参数)

换句话说,
TResult
是函数返回的值的类型。前面的类型(
T
在本例中)是传递给函数的参数类型

在这段代码中,
Foo((personx)=>new{x.LastName,x.DateOfBirth})
,正在向方法
Foo
传递一个带有签名的匿名方法
Func

换句话说,
TResult
包含姓名和出生的匿名类型

由于
Foo
方法需要一个
表达式
,因此在传递给Foo之前,该匿名方法实际上会转换为一个表达式,但这是另一个讨论的故事


您提供的代码返回
string[]{“LastName”,“DateOfBirth”}

解决方案试图以类型化的方式从类中获取属性名称的子集

有几种方法可以做到这一点,但是作者选择了一种非常隐蔽的方法,利用它来节省委托/表达式调用的成本。这就是为什么从未调用
func

为了实现这一点,作者依赖于这样一个事实:泛型类型参数是静态编译的,并且可以通过方法的参数进行推断

本例中的通用参数为
T
是从
(Person x)
(lamda的参数侧)推断出来的,而
TResult
是从
新的{x.LastName,x.DateOfBirth}
(lambda的主体)推断出来的

由于泛型是编译时语言特性,因此该方法可以访问
typeof(TResult)
。。。无需调用/执行表达式

这看起来很棒,工作完成了。然而,同样的事情也可以用一种成本相当低的方法来完成

public static string[] Foo2<T,TResult>(Func<T, TResult> _)
  => typeof(TResult).GetProperties().Select(pi => pi.Name).ToArray();
publicstaticstring[]Foo2(Func)
=>typeof(TResult.GetProperties().Select(pi=>pi.Name.ToArray();
基准

方法 卑鄙 错误 标准偏差 表情 2852.9纳秒 47.68纳秒 44.60纳秒 Func 122.7纳秒 2.47纳秒 2.31纳秒
解决方案是尝试以类型化的方式从类中获取属性名称的子集

有几种方法可以做到这一点,但是作者选择了一种非常隐蔽的方法,利用它来节省委托/表达式调用的成本。这就是为什么从未调用
func

为了实现这一点,作者依赖于这样一个事实:泛型类型参数是静态编译的,并且可以通过方法的参数进行推断

本例中的通用参数为
T
是从
(Person x)
(lamda的参数侧)推断出来的,而
TResult
是从
新的{x.LastName,x.DateOfBirth}
(lambda的主体)推断出来的

由于泛型是编译时语言特性,因此该方法可以访问
typeof(TResult)
。。。无需调用/执行表达式

这看起来很棒,工作完成了。然而,同样的事情也可以用一种成本相当低的方法来完成

public static string[] Foo2<T,TResult>(Func<T, TResult> _)
  => typeof(TResult).GetProperties().Select(pi => pi.Name).ToArray();
publicstaticstring[]Foo2(Func)
=>typeof(TResult.GetProperties().Select(pi=>pi.Name.ToArray();
基准

方法 卑鄙 错误 标准偏差 表情 2852.9纳秒 47.68纳秒 44.60纳秒 Func 122.7纳秒 2.47纳秒 2.31纳秒
TResult
是传入表达式
func
的结果类型。在您的示例中,它将是匿名类型,包含成员
LastName
DateOfBirth
TResult
是传入表达式
func
的结果类型。在您的示例中,它将是匿名类型,包含成员
LastName
DateOfBirth
<代码>公共类Foo3{static string[]Names=typeof(T).GetProperties().Select(pi=>pi.Name).ToArray();}@JeremyLakeman这是一个很好的观点。我打算走一条类似的道路,得出这样的结论:任何缓存都比随意使用反射要好,然而,为了简洁和额外的味道,我提出了
nameof
的极端观点:)。或者找到一种静态缓存名称的方法,例如<代码>公共类Foo3{static string[]Names=typeof(T).GetProperties().Select(pi=>pi.Name).ToArray();}@JeremyLakeman这是一个很好的观点。我打算走一条类似的道路,得出这样的结论:任何cach