繁体   English   中英

Lambda表达式委托强类型vs弱类型隐式转换方法

[英]Lambda Expression Delegate Strong Type vs Weak Type implicit Convert Method

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

以前,参数看起来像:

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}

Convert根本不是一种方法,它是一个UnaryExpression ,确实有理论上的确切原因-装箱/类型强制。 有趣的是,何时生成了表达式树,我们通常知道的隐式事物实际上是显式出现的。

如果您自己构建表达式,则可以通过调用Expression.Convert()获得相同的效果:

创建一个代表类型转换操作的UnaryExpression。

是的,它是转换表达式 ,它代表拳击而不只是拳击。 它包含用户定义的转换等。

例如,如果类型定义了用户定义的转换,则将使用“转换表达式”进行转换。 在这种情况下, 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将为null,因为它只是装箱转换。

转换必须包含在表达式树中,因为object与给定参数不同,但是由于它是通用方法,因此可以通过包含通用return属性来使弱函数变强

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都将由编译器解析

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM