文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

C#值类型、引用类型、泛型、集合的表达式树怎么创建

2023-06-26 07:13

关注

这篇文章主要介绍了C#值类型、引用类型、泛型、集合的表达式树怎么创建的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C#值类型、引用类型、泛型、集合的表达式树怎么创建文章都会有所收获,下面我们一起来看看吧。

一,定义变量

C# 表达式树中,定义一个变量,使用 ParameterExpression

创建变量结点的方法有两种,

Expression.Parameter()Expression.Variable()// 另外,定义一个常量可以使用 Expression.Constant()。

两种方式都是生成 ParameterExpression 类型 Parameter() 和 Variable() 都具有两个重载。他们创建一个 ParameterExpression节点,该节点可用于标识表达式树中的参数或变量。

对于使用定义:

Expression.Variable 用于在块内声明局部变量。

Expression.Parameter用于声明输入值的参数。

先看第一种

        public static ParameterExpression Parameter(Type type)        {            return Parameter(type, name: null);        }                        public static ParameterExpression Variable(Type type)        {            return Variable(type, name: null);        }

从代码来看,没有区别。

再看看具有两个参数的重载

        public static ParameterExpression Parameter(Type type, string name)        {            Validate(type, allowByRef: true);            bool byref = type.IsByRef;            if (byref)            {                type = type.GetElementType();            }            return ParameterExpression.Make(type, name, byref);        }
        public static ParameterExpression Variable(Type type, string name)        {            Validate(type, allowByRef: false);            return ParameterExpression.Make(type, name, isByRef: false);        }

如你所见,两者只有一个 allowByRef 出现了区别,Paramter 允许 Ref, Variable 不允许。

笔者在官方文档和其他作者文章上,都没有找到具体区别是啥,去 stackoverflow 搜索和查看源代码后,确定他们的区别在于 Variable 不能使用 ref 类型。

从字面意思来看,声明一个变量,应该用Expression.Variable, 函数的传入参数应该使用Expression.Parameter

无论值类型还是引用类型,都是这样子定义。

二,访问变量/类型的属性字段和方法

访问变量或类型的属性,使用

Expression.Property()

访问变量/类型的属性或字段,使用

Expression.PropertyOrField()

访问变量或类型的方法,使用

Expression.Call()

访问属性字段和方法

Expression.MakeMemberAccess

他们都返回一个 MemberExpression类型。

使用上,根据实例化/不实例化,有个小区别,上面说了变量或类型。

意思是,已经定义的值类型或实例化的引用类型,是变量;

类型,就是指引用类型,不需要实例化的静态类型或者静态属性字段/方法。

上面的解释不太严谨,下面示例会慢慢解释。

1. 访问属性

使用 Expression.Property() 或 Expression.PropertyOrField()调用属性。

调用静态类型属性

Console 是一个静态类型,Console.Title 可以获取编译器程序的实际位置。

            Console.WriteLine(Console.Title);

使用表达式树表达如下

            MemberExpression member = Expression.Property(null, typeof(Console).GetProperty("Title"));            Expression<Func<string>> lambda = Expression.Lambda<Func<string>>(member);            string result = lambda.Compile()();            Console.WriteLine(result);            Console.ReadKey();

因为调用的是静态类型的属性,所以第一个参数为空。

第二个参数是一个 PropertyInfo 类型。

调用实例属性/字段

C#代码如下

            List<int> a = new List<int>() { 1, 2, 3 };            int result = a.Count;            Console.WriteLine(result);            Console.ReadKey();

在表达式树,调用实例的属性

            ParameterExpression a = Expression.Parameter(typeof(List<int>), "a");            MemberExpression member = Expression.Property(a, "Count");            Expression<Func<List<int>, int>> lambda = Expression.Lambda<Func<List<int>, int>>(member, a);            int result = lambda.Compile()(new List<int> { 1, 2, 3 });            Console.WriteLine(result);            Console.ReadKey();

除了 Expression.Property() ,其他的方式请自行测试,这里不再赘述。

2. 调用函数

使用 Expression.Call() 可以调用一个静态类型的函数或者实例的函数。

调用静态类型的函数

以 Console 为例,调用 WriteLine() 方法

            Console.WriteLine("调用WriteLine方法");            MethodCallExpression method = Expression.Call(                null,                typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),                Expression.Constant("调用WriteLine方法"));            Expression<Action> lambda = Expression.Lambda<Action>(method);            lambda.Compile()();            Console.ReadKey();

Expression.Call() 的重载方法比较多,常用的重载方法是

public static MethodCallExpression Call(Expression instance, MethodInfo method, params Expression[] arguments)

因为要调用静态类型的函数,所以第一个 instance 为空(instance英文意思是实例)。

第二个 method 是要调用的重载方法。

最后一个 arguments 是传入的参数。

调用实例的函数

写一个类

    public class Test    {        public void Print(string info)        {            Console.WriteLine(info);        }    }

调用实例的 Printf() 方法

            Test test = new Test();            test.Print("打印出来");            Console.ReadKey();

表达式表达如下

            ParameterExpression a = Expression.Variable(typeof(Test), "test");            MethodCallExpression method = Expression.Call(                a,                typeof(Test).GetMethod("Print", new Type[] { typeof(string) }),                Expression.Constant("打印出来")                );            Expression<Action<Test>> lambda = Expression.Lambda<Action<Test>>(method,a);            lambda.Compile()(new Test());            Console.ReadKey();

注意的是,Expression.Variable(typeof(Test), "test"); 仅定义了一个变量,还没有初始化/赋值。对于引用类型来说,需要实例化。

上面的方式,是通过外界实例化传入里面的,后面会说如何在表达式内实例化。

三,实例化引用类型

引用类型的实例化,使用 new ,然后选择调用合适的构造函数、设置属性的值。

那么,根据上面的步骤,我们分开讨论。

new

使用 Expression.New()来调用一个类型的构造函数。

他有五个重载,有两种常用重载:

 public static NewExpression New(ConstructorInfo constructor); public static NewExpression New(Type type);

依然使用上面的 Test 类型

            NewExpression newA = Expression.New(typeof(Test));

默认没有参数的构造函数,或者只有一个构造函数,像上面这样调用。

如果像指定一个构造函数,可以

            NewExpression newA = Expression.New(typeof(Test).GetConstructor(xxxxxx));

这里就不详细说了。

给属性赋值

实例化一个构造函数的同时,可以给属性赋值。

        public static MemberInitExpression MemberInit(NewExpression newExpression, IEnumerable<MemberBinding> bindings);        public static MemberInitExpression MemberInit(NewExpression newExpression, params MemberBinding[] bindings);

两种重载是一样的。

我们将 Test 类改成

    public class Test    {        public int sample { get; set; }        public void Print(string info)        {            Console.WriteLine(info);        }    }

然后

            var binding = Expression.Bind(                typeof(Test).GetMember("sample")[0],                Expression.Constant(10)            );

创建引用类型

Expression.MemberInit()

表示调用构造函数并初始化新对象的一个或多个成员。

如果实例化一个类,可以使用

            NewExpression newA = Expression.New(typeof(Test));            MemberInitExpression test = Expression.MemberInit(newA,                new List<MemberBinding>() { }                );

如果要在实例化时给成员赋值

            NewExpression newA = Expression.New(typeof(Test));            // 给 Test 类型的一个成员赋值            var binding = Expression.Bind(                typeof(Test).GetMember("sample")[0],Expression.Constant(10));            MemberInitExpression test = Expression.MemberInit(newA,                new List&lt;MemberBinding&gt;() { binding}                );

示例

实例化一个类型,调用构造函数、给成员赋值,示例代码如下

            // 调用构造函数            NewExpression newA = Expression.New(typeof(Test));            // 给 Test 类型的一个成员赋值            var binding = Expression.Bind(                typeof(Test).GetMember("sample")[0], Expression.Constant(10));            // 实例化一个类型            MemberInitExpression test = Expression.MemberInit(newA,                new List<MemberBinding>() { binding }                );            // 调用方法            MethodCallExpression method1 = Expression.Call(                test,                typeof(Test).GetMethod("Print", new Type[] { typeof(string) }),                Expression.Constant("打印出来")                );            // 调用属性            MemberExpression method2 = Expression.Property(test, "sample");            Expression<Action> lambda1 = Expression.Lambda<Action>(method1);            lambda1.Compile()();            Expression<Func<int>> lambda2 = Expression.Lambda<Func<int>>(method2);            int sample = lambda2.Compile()();            Console.WriteLine(sample);            Console.ReadKey();

四,实例化泛型类型于调用

将 Test 类,改成这样

    public class Test<T>    {        public void Print<T>(T info)        {            Console.WriteLine(info);        }    }

Test 类已经是一个泛型类,表达式实例化示例

        static void Main(string[] args)        {            RunExpression<string>();            Console.ReadKey();        }        public static void RunExpression<T>()        {            // 调用构造函数            NewExpression newA = Expression.New(typeof(Test<T>));            // 实例化一个类型            MemberInitExpression test = Expression.MemberInit(newA,                new List<MemberBinding>() { }                );            // 调用方法            MethodCallExpression method = Expression.Call(                test,                typeof(Test<T>).GetMethod("Print").MakeGenericMethod(new Type[] { typeof(T) }),                Expression.Constant("打印出来")                );            Expression<Action> lambda1 = Expression.Lambda<Action>(method);            lambda1.Compile()();            Console.ReadKey();        }

五,定义集合变量、初始化、添加元素

集合类型使用 ListInitExpression表示。

创建集合类型,需要使用到

ElementInit 表示 IEnumerable集合的单个元素的初始值设定项。

ListInit 初始化一个集合。

C# 中,集合都实现了 IEnumerable,集合都具有 Add 扥方法或属性。

使用 C# 初始化一个集合并且添加元素,可以这样

            List<string> list = new List<string>()            {                "a",                "b"            };            list.Add("666");

而在表达式树里面,是通过 ElementInit 调用 Add 方法初始化/添加元素的。

示例

            MethodInfo listAdd = typeof(List<string>).GetMethod("Add");                        ElementInit add1 = Expression.ElementInit(                listAdd,                Expression.Constant("a"),                Expression.Constant("b")                );            // Add("666")            ElementInit add2 = Expression.ElementInit(listAdd, Expression.Constant("666"));

示例

            MethodInfo listAdd = typeof(List<string>).GetMethod("Add");            ElementInit add1 = Expression.ElementInit(listAdd, Expression.Constant("a"));            ElementInit add2 = Expression.ElementInit(listAdd, Expression.Constant("b"));            ElementInit add3 = Expression.ElementInit(listAdd, Expression.Constant("666"));            NewExpression list = Expression.New(typeof(List<string>));            // 初始化值            ListInitExpression setList = Expression.ListInit(                list,                add1,                add2,                add3                );            // 没啥执行的,就这样看看输出的信息            Console.WriteLine(setList.ToString());            MemberExpression member = Expression.Property(setList, "Count");            Expression<Func<int>> lambda = Expression.Lambda<Func<int>>(member);            int result = lambda.Compile()();            Console.WriteLine(result);            Console.ReadKey();

关于“C#值类型、引用类型、泛型、集合的表达式树怎么创建”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“C#值类型、引用类型、泛型、集合的表达式树怎么创建”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯