C# 从lambda/代码解释返回匿名类型
此代码来自stackoverflow的Lukazoid先生。我想知道这是怎么回事。对我来说,你怎么称呼这样的方法有点奇怪。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(); }
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