亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C#值類型、引用類型、泛型、集合、調(diào)用函數(shù)的表達(dá)式樹(shù)實(shí)踐

 更新時(shí)間:2022年01月18日 11:50:08   作者:癡者工良  
本文詳細(xì)講解了C#值類型、引用類型、泛型、集合、調(diào)用函數(shù)的表達(dá)式樹(shù)實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

一,定義變量

C# 表達(dá)式樹(shù)中,定義一個(gè)變量,使用 ParameterExpression

創(chuàng)建變量結(jié)點(diǎn)的方法有兩種,

Expression.Parameter()
Expression.Variable()
// 另外,定義一個(gè)常量可以使用 Expression.Constant()。

兩種方式都是生成 ParameterExpression 類型 Parameter() 和 Variable() 都具有兩個(gè)重載。他們創(chuàng)建一個(gè) ParameterExpression節(jié)點(diǎn),該節(jié)點(diǎn)可用于標(biāo)識(shí)表達(dá)式樹(shù)中的參數(shù)或變量。

對(duì)于使用定義:

Expression.Variable 用于在塊內(nèi)聲明局部變量。

Expression.Parameter用于聲明輸入值的參數(shù)。

先看第一種

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

從代碼來(lái)看,沒(méi)有區(qū)別。

再看看具有兩個(gè)參數(shù)的重載

        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);
        }

如你所見(jiàn),兩者只有一個(gè) allowByRef 出現(xiàn)了區(qū)別,Paramter 允許 Ref, Variable 不允許。

筆者在官方文檔和其他作者文章上,都沒(méi)有找到具體區(qū)別是啥,去 stackoverflow 搜索和查看源代碼后,確定他們的區(qū)別在于 Variable 不能使用 ref 類型。

從字面意思來(lái)看,聲明一個(gè)變量,應(yīng)該用Expression.Variable, 函數(shù)的傳入?yún)?shù)應(yīng)該使用Expression.Parameter。

無(wú)論值類型還是引用類型,都是這樣子定義。

二,訪問(wèn)變量/類型的屬性字段和方法

訪問(wèn)變量或類型的屬性,使用

Expression.Property()

訪問(wèn)變量/類型的屬性或字段,使用

Expression.PropertyOrField()

訪問(wèn)變量或類型的方法,使用

Expression.Call()

訪問(wèn)屬性字段和方法

Expression.MakeMemberAccess

他們都返回一個(gè) MemberExpression類型。

使用上,根據(jù)實(shí)例化/不實(shí)例化,有個(gè)小區(qū)別,上面說(shuō)了變量或類型。

意思是,已經(jīng)定義的值類型或?qū)嵗囊妙愋?,是變量?/p>

類型,就是指引用類型,不需要實(shí)例化的靜態(tài)類型或者靜態(tài)屬性字段/方法。

上面的解釋不太嚴(yán)謹(jǐn),下面示例會(huì)慢慢解釋。

1. 訪問(wèn)屬性

使用 Expression.Property() 或 Expression.PropertyOrField()調(diào)用屬性。

調(diào)用靜態(tài)類型屬性

Console 是一個(gè)靜態(tài)類型,Console.Title 可以獲取編譯器程序的實(shí)際位置。

            Console.WriteLine(Console.Title);

使用表達(dá)式樹(shù)表達(dá)如下

            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();

因?yàn)檎{(diào)用的是靜態(tài)類型的屬性,所以第一個(gè)參數(shù)為空。

第二個(gè)參數(shù)是一個(gè) PropertyInfo 類型。

調(diào)用實(shí)例屬性/字段

C#代碼如下

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

在表達(dá)式樹(shù),調(diào)用實(shí)例的屬性

            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() ,其他的方式請(qǐng)自行測(cè)試,這里不再贅述。

2. 調(diào)用函數(shù)

使用 Expression.Call() 可以調(diào)用一個(gè)靜態(tài)類型的函數(shù)或者實(shí)例的函數(shù)。

調(diào)用靜態(tài)類型的函數(shù)

以 Console 為例,調(diào)用 WriteLine() 方法

            Console.WriteLine("調(diào)用WriteLine方法");

            MethodCallExpression method = Expression.Call(
                null,
                typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
                Expression.Constant("調(diào)用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)

因?yàn)橐{(diào)用靜態(tài)類型的函數(shù),所以第一個(gè) instance 為空(instance英文意思是實(shí)例)。

第二個(gè) method 是要調(diào)用的重載方法。

最后一個(gè) arguments 是傳入的參數(shù)。

調(diào)用實(shí)例的函數(shù)

寫一個(gè)類

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

調(diào)用實(shí)例的 Printf() 方法

            Test test = new Test();
            test.Print("打印出來(lái)");
            Console.ReadKey();

表達(dá)式表達(dá)如下

            ParameterExpression a = Expression.Variable(typeof(Test), "test");

            MethodCallExpression method = Expression.Call(
                a,
                typeof(Test).GetMethod("Print", new Type[] { typeof(string) }),
                Expression.Constant("打印出來(lái)")
                );

            Expression<Action<Test>> lambda = Expression.Lambda<Action<Test>>(method,a);
            lambda.Compile()(new Test());
            Console.ReadKey();

注意的是,Expression.Variable(typeof(Test), "test"); 僅定義了一個(gè)變量,還沒(méi)有初始化/賦值。對(duì)于引用類型來(lái)說(shuō),需要實(shí)例化。

上面的方式,是通過(guò)外界實(shí)例化傳入里面的,后面會(huì)說(shuō)如何在表達(dá)式內(nèi)實(shí)例化。

三,實(shí)例化引用類型

引用類型的實(shí)例化,使用 new ,然后選擇調(diào)用合適的構(gòu)造函數(shù)、設(shè)置屬性的值。

那么,根據(jù)上面的步驟,我們分開(kāi)討論。

new

使用 Expression.New()來(lái)調(diào)用一個(gè)類型的構(gòu)造函數(shù)。

他有五個(gè)重載,有兩種常用重載:

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

依然使用上面的 Test 類型

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

默認(rèn)沒(méi)有參數(shù)的構(gòu)造函數(shù),或者只有一個(gè)構(gòu)造函數(shù),像上面這樣調(diào)用。

如果像指定一個(gè)構(gòu)造函數(shù),可以

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

這里就不詳細(xì)說(shuō)了。

給屬性賦值

實(shí)例化一個(gè)構(gòu)造函數(shù)的同時(shí),可以給屬性賦值。

        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)
            );

創(chuàng)建引用類型

Expression.MemberInit()

表示調(diào)用構(gòu)造函數(shù)并初始化新對(duì)象的一個(gè)或多個(gè)成員。

如果實(shí)例化一個(gè)類,可以使用

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

如果要在實(shí)例化時(shí)給成員賦值

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

            // 給 Test 類型的一個(gè)成員賦值
            var binding = Expression.Bind(
                typeof(Test).GetMember("sample")[0],Expression.Constant(10));

            MemberInitExpression test = Expression.MemberInit(newA,
                new List&lt;MemberBinding&gt;() { binding}
                );

示例

實(shí)例化一個(gè)類型,調(diào)用構(gòu)造函數(shù)、給成員賦值,示例代碼如下

            // 調(diào)用構(gòu)造函數(shù)
            NewExpression newA = Expression.New(typeof(Test));

            // 給 Test 類型的一個(gè)成員賦值
            var binding = Expression.Bind(
                typeof(Test).GetMember("sample")[0], Expression.Constant(10));

            // 實(shí)例化一個(gè)類型
            MemberInitExpression test = Expression.MemberInit(newA,
                new List<MemberBinding>() { binding }
                );

            // 調(diào)用方法
            MethodCallExpression method1 = Expression.Call(
                test,
                typeof(Test).GetMethod("Print", new Type[] { typeof(string) }),
                Expression.Constant("打印出來(lái)")
                );

            // 調(diào)用屬性
            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();

四,實(shí)例化泛型類型于調(diào)用

將 Test 類,改成這樣

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

Test 類已經(jīng)是一個(gè)泛型類,表達(dá)式實(shí)例化示例

        static void Main(string[] args)
        {
            RunExpression<string>();
            Console.ReadKey();
        }
        public static void RunExpression<T>()
        {
            // 調(diào)用構(gòu)造函數(shù)
            NewExpression newA = Expression.New(typeof(Test<T>));

            // 實(shí)例化一個(gè)類型
            MemberInitExpression test = Expression.MemberInit(newA,
                new List<MemberBinding>() { }
                );

            // 調(diào)用方法
            MethodCallExpression method = Expression.Call(
                test,
                typeof(Test<T>).GetMethod("Print").MakeGenericMethod(new Type[] { typeof(T) }),
                Expression.Constant("打印出來(lái)")
                );

            Expression<Action> lambda1 = Expression.Lambda<Action>(method);
            lambda1.Compile()();

            Console.ReadKey();
        }

五,定義集合變量、初始化、添加元素

集合類型使用 ListInitExpression表示。

創(chuàng)建集合類型,需要使用到

ElementInit 表示 IEnumerable集合的單個(gè)元素的初始值設(shè)定項(xiàng)。

ListInit 初始化一個(gè)集合。

C# 中,集合都實(shí)現(xiàn)了 IEnumerable,集合都具有 Add 扥方法或?qū)傩浴?/p>

使用 C# 初始化一個(gè)集合并且添加元素,可以這樣

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

而在表達(dá)式樹(shù)里面,是通過(guò) ElementInit 調(diào)用 Add 方法初始化/添加元素的。

示例

            MethodInfo listAdd = typeof(List<string>).GetMethod("Add");

            /*
             * new List<string>()
             * {
             *     "a",
             *     "b"
             * };
             */
            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
                );
            // 沒(méi)啥執(zhí)行的,就這樣看看輸出的信息
            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();

 到此這篇關(guān)于C#值類型、引用類型、泛型、集合、調(diào)用函數(shù)的表達(dá)式樹(shù)實(shí)踐的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論