我有一个用于获取强类型Expression<Func<>>
参数的扩展方法但是出于实现原因,我不得不将其更改为使用弱类型版本。这对表达式参数产生了一种奇怪的影响,因为它现在似乎将lambda表达式包装在显式调用“转换”中。方法
以前的参数看起来像:
m => m.Data
现在看起来如下:
m => Convert(m.Data)
我已使用以下示例代码复制了该问题:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace ConsoleApplication
{
static class Program
{
static void Main(string[] args)
{
Model model = new Model()
{
Data = 123
};
Test(m => m.Data, m => m.Data);
Console.ReadLine();
}
public static void Test<TProperty>(Expression<Func<Model, TProperty>> strongTyped, Expression<Func<Model, object>> weakTyped)
{
Console.WriteLine("Strong Typed: {0}", strongTyped);
Console.WriteLine("Weak Typed: {0}", weakTyped);
}
}
public class Model
{
public int Data
{
get;
set;
}
}
}
其输出如下:
Strong Typed: m => m.Data
Weak Typed: m => Convert(m.Data)
我猜它与将值类型自动装入对象类型有关。任何人都可以证实这一点,或者有人知道发生了什么事吗?也有人知道Convert方法的声明在哪里吗?
在弱类型表达式上调用compile方法提供以下内容:
weakTyped.Compile().Method
{System.Object lambda_method(System.Runtime.CompilerServices.Closure, ConsoleApplication.Model)}
[System.Reflection.Emit.DynamicMethod.RTDynamicMethod]: {System.Object lambda_method(System.Runtime.CompilerServices.Closure, ConsoleApplication.Model)}
base {System.Reflection.MethodBase}: {System.Object lambda_method(System.Runtime.CompilerServices.Closure, ConsoleApplication.Model)}
MemberType: Method
ReturnParameter: null
ReturnType: {Name = "Object" FullName = "System.Object"}
ReturnTypeCustomAttributes: {System.Reflection.Emit.DynamicMethod.RTDynamicMethod.EmptyCAHolder}
答案 0 :(得分:3)
Convert
根本不是一种方法 - 它只是一个UnaryExpression,而且确实是你理论化的原因 - 拳击/类型强制。有趣的是,当生成表达式树时,我们通常知道隐含的东西实际上是显式出现的。
如果您自己构建表达式,可以通过调用Expression.Convert()
来获得相同的效果:
创建表示类型转换操作的UnaryExpression。
答案 1 :(得分:2)
是的,Conversion expression代表拳击,而不仅仅是拳击。它包含用户定义的转换等。
例如,如果某个类型定义了将使用“转换表达式”进行转换的用户定义转换。在这种情况下,weakTyped.Body.Method
将返回重载方法,例如op_Implicit...
您可以使用以下代码证明这一点。
public static void Test<TProperty>(Expression<Func<Model, TProperty>> strongTyped, Expression<Func<Model, object>> weakTyped)
{
var expr = (UnaryExpression)weakTyped.Body;
Console.WriteLine("Weak Typed method: {0}", expr.Method);
Console.WriteLine("Strong Typed: {0}", strongTyped);
Console.WriteLine("Weak Typed: {0}", weakTyped);
}
public static void TestFloat<TProperty>(Expression<Func<Model, TProperty>> strongTyped, Expression<Func<Model, decimal>> weakTyped)
{
var expr = (UnaryExpression) weakTyped.Body;
Console.WriteLine("Weak Typed method: {0}", expr.Method);
Console.WriteLine("Strong Typed: {0}", strongTyped);
Console.WriteLine("Weak Typed: {0}", weakTyped);
}
对于十进制类型,这将返回重载运算符,因为object
weakTyped.Body.Method
将为空,因为它只是一个装箱转换。
答案 2 :(得分:0)
转换必须包含在表达式树中,因为对象与给定参数不同,但由于它是一个通用方法,您可以通过包含泛型返回属性来强弱(
)public static void Test<TProperty, TReturnValue>(Expression<Func<Model, TProperty>> strongTyped, Expression<Func<Model, TReturnValue>> weakTyped)
{
Console.WriteLine("Strong Typed: {0}", strongTyped);
Console.WriteLine("Weak (now also strong) Typed: {0}", weakTyped);
}
您仍然可以使用相同的调用Test(m => m.Data, m => m.Data);
,编译器将解析TProperty和TReturnValue