【c#表达式树】最完善的表达式树Expression.Dynamic的玩法

这篇具有很好参考价值的文章主要介绍了【c#表达式树】最完善的表达式树Expression.Dynamic的玩法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

引言

    在我第一次写博客的时候,写的第一篇文章,就是关于表达式树的,链接:https://www.cnblogs.com/1996-Chinese-Chen/p/14987967.html,其中,当时一直没有研究Expression.Dynamic的使用方法(因为网上找不到资料),就了解到是程序运行时动态去构建表达式树,举个例子,例如我们需要在我们的查询条件中去构建他是等于或者不等于,这个时候,虽然我们可以定义等于或者不定于 的BinaryExpression,然后在代码中通过switch去进行判断,使用的是Equal还是NotEqual,这中间还需要我们自己去写一个switch,如果使用了Dynamic的方法,我们就只需要找到对应的ExpressionType然后传入创建Binder的方法中,在调用Dynamic方法就可以动态的实现,各种判断操作,或者其他的调用方法,灵活度比switch更高,接下来,我们就看看如何使用Expression.Dynamic方法来实现各种操作吧,一下所有代码操作需要引入Microsoft.CSharp.RuntimeBinder,nuget搜索Microsoft.CSharp即可。方便测试,我新建了一个Test的类,下面会用到

public class Test
{
    private List<string> Strings = new List<string>();
    public event Action TestEvent;
    public Test(int a,int b)
    {
        A = a;
        B = b;
        Strings.Add("1");
        Strings.Add("2");
        Strings.Add("3");
    }
    public string this[int Index] { get=> Strings[Index]; set=> Strings[Index]=value; }
    public int A { get; set; }
    public int B { get; set; }

    public int Add()
    {
        return A+B;
    }
    public static int AddOne()
    {
        return 15;
    }
}

 文章来源地址https://www.toymoban.com/news/detail-410677.html

二元运算

    下面的代码实现一个二元运算,首先Dynamic方法是需要CallBinder参数的,而对应的实现有如下的Binder,我们首先需要去创建对应的Binder,二元运算就使用BinaryOperation方法创建,CSharpBinderFlags是一个枚举类型,它用于指定动态绑定操作的行为,里面可以定义在动态绑定的时候需要执行的一些特殊操作,例如,运算应该在已经检查的上下文中运行,或者使用Invoke等需要使用的一些特殊操作,或者转换的时候等等。第二个参数是ExpressionType,标明我们是那一个二元运算,第三个是当前代码运行的主体类型 that indicates where this operation is used.即这个指示了这个操作被用在哪些地方。第三个是一个CSharpArgumentInfo集合,是我们创建这个站点的时候需要使用的参数数量,如果是调用方法的时候,或者获取实例属性的时候,第一个参数是为实例参数,UseCompileTimeType类型是编译期间确定类型,其中还有IsStaticType,IsRef,IsOUt等各种,供我们使用。

    然后我们创建一个dynamic的Expression,传入binder,返回类型是object,然后传入需要计算的两个参数10和1,最后得到委托,运行委托即可。

 CallSiteBinder binder = Binder.BinaryOperation(
                    CSharpBinderFlags.None,
                    ExpressionType.LeftShift,
                    typeof(Program),
                    new[]
                    {
                CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null),
                CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null)
                    });

        var dynamic = Expression.Dynamic(binder, typeof(object), Expression.Constant(10), Expression.Constant(1));

        Func<int> func = Expression.Lambda<Func<int>>(Expression.Convert(dynamic, typeof(int))).Compile();
        Console.WriteLine(func());

 【c#表达式树】最完善的表达式树Expression.Dynamic的玩法

 

创建实例

    从上面的Test类看到,我们定义了两个入参,可能有的人会问了为什么入参是两个Binder为什么定义了三个呢,这是因为,创建性的Binder在创建的时候 参数第一个必须是类型参数,所以此处第一个参数必须是Test的type,然后后面是Static类型的参数,

最后一个参数就是3,调用Dynamic,第二个为返回类型的参数,然后传入对应的参数即可创建对象。

  static int A = 5; 

var constructorBinder = Binder.InvokeConstructor(CSharpBinderFlags.None, typeof(Program), new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType,null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.IsStaticType,null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType,null) }); var createInstance = Expression.Dynamic(constructorBinder, typeof(Test), Expression.Constant(typeof(Test)), Expression.Constant(A), Expression.Constant(3)); var instance = Expression.Lambda<Func<Test>>(createInstance).Compile()();

 

 调用方法

  实例方法

      实例方法,使用InvokeMember,第二个参数是调用的方法名称,第三个参数是参数类型,由于我没有定义参数所以为null,然后实例方法我们需要定义一个实例参数,在CSharpArgumentInfo定义,然后调用Dynamic,返回类型必须是Object,因为这块扯犊子的是他直接写死的,如果需要转只有自己到表达式树那块Convert转,调用然后生成委托,返回结果。

var invokeBinder = Binder.InvokeMember(
            CSharpBinderFlags.None,
            "Add",
            null,
            typeof(Program),
            new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });
        var invokeDynamic=Expression.Dynamic(invokeBinder, typeof(object),Expression.Constant(instance));
        var returnVal = Expression.Lambda<Func<object>>(invokeDynamic).Compile()();
        Console.WriteLine(returnVal);

  静态方法

      大体上没有区别,在参数类型需要标记为StaticType。传入的参数不再是实例,而是静态方法所属的类型下,可以看到,返回类型必须是Object,我自己在最后Convert了,源码中的Binder默认写死Object

 var invokeStaticBinder = Binder.InvokeMember(
            CSharpBinderFlags.None,
            "AddOne",
            null,
            typeof(Test),
            new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.IsStaticType, null) });
        var invokeStaticDynamic = Expression.Dynamic(invokeStaticBinder, typeof(object),Expression.Constant(typeof(Test)));
        var Val = Expression.Lambda<Func<int>>(Expression.Convert(invokeStaticDynamic,typeof(int))).Compile()();
        Console.WriteLine(Val);

转换

    将int转换为Object类型。

   var bindConvert = Binder.Convert(CSharpBinderFlags.None,typeof(object),typeof(Program));
        var expressConvert = Expression.Dynamic(bindConvert,typeof(object),Expression.Constant(A));
        var funcVal=Expression.Lambda<Func<object>>(expressConvert).Compile()();

Set Get属性

    下面是Set,第二个参数是设置的属性名称,参数类型是实例,以及设置的属性值,最后生成委托,然后调用即可。

   var bindSet = Binder.SetMember(CSharpBinderFlags.None, "A", typeof(Program), new[]
        {
            CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
             CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
        });
        var setExpress = Expression.Dynamic(bindSet,typeof(void), Expression.Constant(instance),Expression.Constant(100));
        var action = Expression.Lambda<Action>(setExpress).Compile();
        action();

    然后是Get,参数是实例的,然后返回就行了。

   var bindGet = Binder.GetMember(CSharpBinderFlags.None, "A", typeof(Program), new[]
        {
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
        });
        var getExpress = Expression.Dynamic(bindGet, typeof(object), Expression.Constant(instance));
        var getFunc= Expression.Lambda<Func<object>>(getExpress).Compile()();
        Console.WriteLine(getFunc);

一元运算

 

    一元运算的ExpressionType,参数的定义,Binder和表达式树绑定,生成委托。

  var NegateBinder = Binder.UnaryOperation(CSharpBinderFlags.None,ExpressionType.Negate,typeof(Program),new[]
        {
            CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null)
        });
        var NegateExpress = Expression.Dynamic(NegateBinder, typeof(object), Expression.Constant(10));
        var NegateVal = Expression.Lambda<Func<object>>(NegateExpress).Compile()();

Get Set Index

  

    先Set,第一个参数自变量,第二个为索引,第三个是具体的值,然后表达式树和Binder绑定,生成委托,调用,即可,可以看到上面Test我们定义了一个Index的。

 var setIndex = Binder.SetIndex(CSharpBinderFlags.None, typeof(Test), new[]
        {
             CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
            CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
            CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
        });
        var setIndexExpress = Expression.Dynamic(setIndex,typeof(void),Expression.Constant(instance),Expression.Constant(1),Expression.Constant("cxd"));
        var SetIndexaction = Expression.Lambda<Action>(setIndexExpress).Compile();
        SetIndexaction();

 

    然后是get,自变量,索引,生成委托,返回索引的值。

  var getIndex= Binder.GetIndex(CSharpBinderFlags.None, typeof(Program), new[]
        {
             CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
            CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
        });
        var getIndexExpress = Expression.Dynamic(getIndex, typeof(object), Expression.Constant(instance), Expression.Constant(0));
        var getIndexaction = Expression.Lambda<Func<object>>(getIndexExpress).Compile()();

IsEvent

    判断属性是不是事件类型的,第二个是属性名称,返回值是bool。

      var isevent = Binder.IsEvent(CSharpBinderFlags.None, "TestEvent", typeof(Program));//换成非Event就不行
        var iseventExpress = Expression.Dynamic(isevent,typeof(bool),Expression.Constant(instance));
        var res=Expression.Lambda<Func<bool>>(iseventExpress).Compile()();
        Console.WriteLine(res);

Invoke

    这个是用来调用委托的,我们定义一个Func的委托,可惜的是,返回值还是只能是object,然后参数参数,然后调用委托,就返回了111。

 var actions= new Func<object>(()=>111);
        var invokeOtherBinder = Binder.Invoke(CSharpBinderFlags.None,typeof(Program),new[]
        {
             CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null),
        });
        var expression = Expression.Dynamic(invokeOtherBinder, typeof(object),Expression.Constant(actions));
        var ra=Expression.Lambda<Func<object>>(expression).Compile()();

结尾

    下次再见,欢迎大家加群讨论,我是四川观察,感谢各位看官的支持,谢谢大家,咱们下次再见。

【c#表达式树】最完善的表达式树Expression.Dynamic的玩法【c#表达式树】最完善的表达式树Expression.Dynamic的玩法

 

到了这里,关于【c#表达式树】最完善的表达式树Expression.Dynamic的玩法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于Expression Lambda表达式树的通用复杂动态查询构建器——《构思篇一》

    在 上一篇 中 构思了把查询子句描述出来的数据结构,那么能否用代码将其表达出来,如何表达呢? 再次回顾考察,看下面的查询子句: 如上所示,有两个 独立的 条件 分别为 Id1 和 Id10 ,用一个逻辑操作符 and 连接起来。 再看下面这条,后面也是两个独立条件通过操作符

    2024年02月06日
    浏览(32)
  • 基于Expression Lambda表达式树的通用复杂动态查询构建器——《构思篇一》[已开源]

    在 上一篇 中 构思了把查询子句描述出来的数据结构,那么能否用代码将其表达出来,如何表达呢? 再次回顾考察,看下面的查询子句: 如上所示,有两个 独立的 条件 分别为 Id1 和 Id10 ,用一个逻辑操作符 and 连接起来。 再看下面这条,后面也是两个独立条件通过操作符

    2024年02月06日
    浏览(47)
  • 基于Expression Lambda表达式树的通用复杂动态查询构建器——《原型篇一》[已开源]

    续接上编,本篇来讲讲俄罗斯套娃的设计与实现。 首先简单地完善一下前面提到的例子,代码如下: 测试实体类 独立条件类 条件组类 枚举   接下来,先构建查询条件描述器对象,由于例子代码比较简略,仅用于方便说明设计思路和方法,如果哪位看官直接拿来实用,请先备

    2024年02月06日
    浏览(38)
  • 基于Expression Lambda表达式树的通用复杂动态查询构建器——《构思篇二》已开源

    接续[上篇之预告] 本篇来讲讲,如何根据前面设计的查询描述器构造出可执行的表达式。正如标题所示,实现手段将采用 Expression Lambda 技术。 先来看看主角 System.Linq.Expressions.Expression 长什么样,都有些什么东西,能做什么。 先看看它的类图: System.Linq.Expressions.ConstantExpres

    2024年02月06日
    浏览(40)
  • LangChain 67 深入理解LangChain 表达式语言30 调用tools搜索引擎 LangChain Expression Language (LCEL)

    LangChain系列文章 LangChain 50 深入理解LangChain 表达式语言十三 自定义pipeline函数 LangChain Expression Language (LCEL) LangChain 51 深入理解LangChain 表达式语言十四 自动修复配置RunnableConfig LangChain Expression Language (LCEL) LangChain 52 深入理解LangChain 表达式语言十五 Bind runtime args绑定运行时参数

    2024年01月23日
    浏览(73)
  • Java中使用MapStruct实现对象转换时使用@Mapping的expression表达式实现自定义转换规则(多对一、获取当前Date)

    Java中使用MapStruct实现对象转换/实体属性赋值/Bean属性映射,避免大量setter和getter: Java中使用MapStruct实现对象转换/实体属性赋值/Bean属性映射,避免大量setter和getter_霸道流氓气质的博客-CSDN博客 上面介绍了mapstruct的简单使用,某些场景下需要自定义转换规则,比如记录时间字

    2024年02月14日
    浏览(44)
  • 【C#基础】C# 正则表达式

    序号 系列文章 7 【C#基础】C# 常用数据结构 8 【C#基础】C# 面向对象编程 9 【C# 基础】C# 异常处理操作 🌼 hello大家好啊,我是writer桑。前面一章已经学习了 C# 中的异常处理操作,那本章就开始学习 C# 程序中正则表达式的应用。关于正则表达式网上已经有很多现成的学习资源

    2024年02月03日
    浏览(37)
  • c# 动态表达式

    准备: 创建一个空项目,nuget查找并安装ExpressionEvaluator 示例: using ExpressionEvaluator; using System;  一、计算简单表达式        public string Test1()         {             return SimpleEval(\\\"0.1*(Math.Pow(10,2)+20)\\\");         }         /// summary         /// 简单数值计算         /// /summ

    2024年02月07日
    浏览(34)
  • C#表达式树

    C# 表达式树是 .NET 框架中的一项强大的功能,我们可以利用表达式树来动态生成 lambda 表达式和 LINQ 查询语句,这极大的方便了我们动态构建数据查询和过滤的逻辑。本文将从基本用法和高级用法两个方面来介绍 C# 表达式树。 首先,我们需要了解  Expression  类型,这个类型

    2024年02月02日
    浏览(25)
  • c#高级-正则表达式

    正则表达式是由普通字符和元字符(特殊符号)组成的文字形式 应用场景 1.用于验证输入的邮箱是否合法。 2.用于验证输入的电话号码是否合法。 3.用于验证输入的身份证号码是否合法。等等 正则表达式常用的限定符总结:    几种常用的正则简写表达式总结: 如下图所示

    2024年02月22日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包