C# Lambda表达式委托强类型与弱类型隐式转换方法

C# Lambda表达式委托强类型与弱类型隐式转换方法,c#,lambda,C#,Lambda,我有一个扩展方法,用于获取强类型的表达式参数,但是出于实现原因,我不得不将其更改为使用弱类型版本。这对expression参数产生了奇怪的影响,因为它现在似乎将lambda表达式包装在对“Convert”方法的显式调用中 以前,参数看起来像: m => m.Data 现在看起来是这样的: m => Convert(m.Data) weakTyped.Compile().Method {System.Object lambda_method(System.Runtime.Compi

我有一个扩展方法,用于获取强类型的
表达式
参数,但是出于实现原因,我不得不将其更改为使用弱类型版本。这对expression参数产生了奇怪的影响,因为它现在似乎将lambda表达式包装在对“Convert”方法的显式调用中

以前,参数看起来像:

m => m.Data
现在看起来是这样的:

m => Convert(m.Data)
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}
我已使用以下示例代码复制了该问题:

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;
        }
    }
}
我猜这与将值类型自动装箱到对象类型有关。有人能证实这一点吗?或者有人知道发生了什么事吗?还有人知道Convert方法在哪里声明吗

对弱类型表达式调用compile方法会产生以下结果:

m => Convert(m.Data)
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}

Convert
根本不是一种方法——它是一种方法,事实上这正是你理论化的原因——装箱/类型强制。有趣的是,在生成表达式树时,我们通常知道的隐式内容实际上是显式的

如果您自己构建表达式,则可以通过调用以下命令获得相同的效果:

创建表示类型转换操作的UnaryExpression


转换必须包含在表达式树中,因为对象与给定参数不同,但由于它是一个泛型方法,因此可以通过包含泛型返回属性使弱-强转换

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);
}
公共静态无效测试(表达式strongTyped,表达式weakTyped)
{
WriteLine(“强类型:{0}”,强类型);
WriteLine(“弱(现在也是强)类型:{0}”,弱类型);
}
您仍然可以使用相同的调用
Test(m=>m.Data,m=>m.Data),并且TProperty和TReturnValue都将由编译器解析

是的,它代表装箱,而不仅仅是装箱。它包含用户定义的转换等

例如,如果类型定义了将使用“转换表达式”转换的用户定义转换。在本例中,
weakTyped.Body.Method
将返回重载方法,类似于
op\u 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);
}
公共静态无效测试(表达式strongTyped,表达式weakTyped)
{
var expr=(UnaryExpression)weakTyped.Body;
WriteLine(“弱类型方法:{0}”,expr.method);
WriteLine(“强类型:{0}”,强类型);
WriteLine(“弱类型:{0}”,弱类型);
}
公共静态void TestFloat(表达式strongTyped、表达式weakTyped)
{
var expr=(UnaryExpression)weakTyped.Body;
WriteLine(“弱类型方法:{0}”,expr.method);
WriteLine(“强类型:{0}”,强类型);
WriteLine(“弱类型:{0}”,弱类型);
}

对于decimal类型,这将返回重载运算符,其中as
object
weakTyped.Body.Method
将为null,因为它只是一个装箱转换。

谢谢-这很有意义。我没有意识到自动装箱会应用于表达式,我假设在计算表达式时它会应用于结果。@TomMaher yep。我还能做些什么来回答这个问题吗?不,没关系,我只是想知道发生了什么,转换“方法”从哪里来。再次感谢。感谢您的回复-不幸的是,我不得不将表达式保留为弱形式,因为我希望将一个表达式数组作为参数传入,所有这些表达式都具有可能不同的返回类型:
Test(此TModel模型,params expression[]props)