国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - C# - 利用lambda表達(dá)式樹優(yōu)化反射詳解

利用lambda表達(dá)式樹優(yōu)化反射詳解

2022-03-06 13:32Fode C#

這篇文章主要給大家介紹了關(guān)于如何利用lambda表達(dá)式樹優(yōu)化反射的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

本節(jié)重點不講反射機(jī)制,而是講lambda表達(dá)式樹來替代反射中常用的獲取屬性和方法,來達(dá)到相同的效果但卻比反射高效。

每個人都知道,用反射調(diào)用一個方法或者對屬性執(zhí)行setvalue和getvalue操作的時候都會比直接調(diào)用慢很多,這其中設(shè)計到clr中內(nèi)部的處理,不做深究。然而,我們在某些情況下又無法不使用反射,比如:在一個orm框架中,你要將一個datarow轉(zhuǎn)化為一個對象,但你又不清楚該對象有什么屬性,這時候你就需要寫一個通用的泛型方法來處理,以下代碼寫得有點惡心,但不妨礙理解意思:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//將datareader轉(zhuǎn)化為一個對象
     private static t getobj<t>(sqlitedatareader reader) where t : class
 {
  t obj = new t();
  propertyinfo[] pros = obj.gettype().getproperties();
  foreach (propertyinfo item in pros)
  {
  try
  {
   int32 index = reader.getordinal(item.name);
   string result = reader.getstring(index);
   if (typeof(string) == item.propertytype)
   {
   item.setvalue(obj, result);
   continue;
   }
   if (typeof(datetime) == item.propertytype)
   {
   item.setvalue(obj, convert.todatetime(result));
   continue;
   }
   if (typeof(boolean) == item.propertytype)
   {
   item.setvalue(obj, convert.toboolean(result));
   continue;
   }
   if (typeof(int32) == item.propertytype)
   {
   item.setvalue(obj, convert.toint32(result));
   continue;
   }
   if (typeof(single) == item.propertytype)
   {
   item.setvalue(obj, convert.tosingle(result));
   continue;
   }
   if (typeof(single) == item.propertytype)
   {
   item.setvalue(obj, convert.tosingle(result));
   continue;
   }
   if (typeof(double) == item.propertytype)
   {
   item.setvalue(obj, convert.todouble(result));
   continue;
   }
   if (typeof(decimal) == item.propertytype)
   {
   item.setvalue(obj, convert.todecimal(result));
   continue;
   }
   if (typeof(byte) == item.propertytype)
   {
   item.setvalue(obj, convert.tobyte(result));
   continue;
   }
  }
  catch (argumentoutofrangeexception ex)
  {
   continue;
  }
  }
  return obj;
 }

對于這種情況,其執(zhí)行效率是特別低下的,具體多慢在下面例子會在.net core平臺上和.net framework4.0運(yùn)行測試案例.對于以上我舉例的情況,效率上我們還可以得到提升。但對于想在運(yùn)行時修改一下屬性的名稱或其他操作,反射還是一項特別的神器,因此在某些情況下反射還是無法避免的。

但是對于只是簡單的setvalue或者getvalue,包括用反射構(gòu)造函數(shù),我們可以想一個中繼的方法,那就是使用表達(dá)式樹。對于不理解表達(dá)式樹的,可以到微軟文檔查看,。表達(dá)式樹很容易通過對象模型表示表達(dá)式,因此強(qiáng)烈建議學(xué)習(xí)。查看以下代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
static void main()
 {
  dog dog = new dog();
  propertyinfo propertyinfo = dog.gettype().getproperty(nameof(dog.name)); //獲取對象dog的屬性
  methodinfo settermethodinfo = propertyinfo.getsetmethod(); //獲取屬性name的set方法
 
  parameterexpression param = expression.parameter(typeof(dog), "param");
  expression getpropertyvalueexp = expression.lambda(expression.property(param, nameof(dog.name)), param);
  expression<func<dog, string>> getpropertyvaluelambda = (expression<func<dog, string>>)getpropertyvalueexp;
  parameterexpression paramo = expression.parameter(typeof(dog), "param");
  parameterexpression parami = expression.parameter(typeof(string), "newvalue");
  methodcallexpression methodcallsetterofproperty = expression.call(paramo, settermethodinfo, parami);
  expression setpropertyvalueexp = expression.lambda(methodcallsetterofproperty, paramo, parami);
  expression<action<dog, string>> setpropertyvaluelambda = (expression<action<dog, string>>)setpropertyvalueexp;
 
  //創(chuàng)建了屬性name的get方法表達(dá)式和set方法表達(dá)式,當(dāng)然只是最簡單的
  func<dog, string> getter = getpropertyvaluelambda.compile();
  action<dog, string> setter = setpropertyvaluelambda.compile();
 
  setter?.invoke(dog, "wlj"); //我們現(xiàn)在對dog這個對象的name屬性賦值
  string dogname = getter?.invoke(dog); //獲取屬性name的值
  
  console.writeline(dogname);
  console.readkey();
 }
 
 public class dog
 {
  public string name { get; set; }
 }

以下代碼可能很難看得懂,但只要知道我們創(chuàng)建了屬性的get、set這兩個方法就行,其結(jié)果最后也能輸出狗的名字 wlj,擁有expressiontree的好處是他有一個名為compile()的方法,它創(chuàng)建一個代表表達(dá)式的代碼塊。現(xiàn)在是最有趣的部分,假設(shè)你在編譯時不知道類型(在這篇文章中包含的代碼我在不同的程序集上創(chuàng)建了一個類型)你仍然可以應(yīng)用這種技術(shù),我將對于常用的屬性的set,get操作進(jìn)行分裝。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/// <summary>
   /// 屬性類,仿造反射中的propertyinfo
 /// </summary>
   public class property
 {
 
  private readonly propertygetter getter;
  private readonly propertysetter setter;
  public string name { get; private set; }
 
  public propertyinfo info { get; private set; }
 
  public property(propertyinfo propertyinfo)
  {
   if (propertyinfo == null)
    throw new nullreferenceexception("屬性不能為空");
   this.name = propertyinfo.name;
   this.info = propertyinfo;
   if (this.info.canread)
   {
    this.getter = new propertygetter(propertyinfo);
   }
 
   if (this.info.canwrite)
   {
    this.setter = new propertysetter(propertyinfo);
   }
  }
 
 
  /// <summary>
     /// 獲取對象的值
  /// </summary>
    /// <param name="instance"></param>
    /// <returns></returns>
     public object getvalue(object instance)
  {
   return getter?.invoke(instance);
  }
 
 
  /// <summary>
     /// 賦值操作
  /// </summary>
    /// <param name="instance"></param>
    /// <param name="value"></param>
     public void setvalue(object instance, object value)
  {
   this.setter?.invoke(instance, value);
  }
 
  private static readonly concurrentdictionary<type, core.reflection.property[]> securitycache = new concurrentdictionary<type, property[]>();
 
  public static core.reflection.property[] getproperties(type type)
  {
   return securitycache.getoradd(type, t => t.getproperties().select(p => new property(p)).toarray());
  }
 
 }
 
  /// <summary>
   /// 屬性get操作類
  /// </summary>
    public class propertygetter
  {
  private readonly func<object, object> funcget;
 
  public propertygetter(propertyinfo propertyinfo) : this(propertyinfo?.declaringtype, propertyinfo.name)
  {
 
  }
 
  public propertygetter(type declaretype, string propertyname)
  {
   if (declaretype == null)
   {
    throw new argumentnullexception(nameof(declaretype));
   }
   if (propertyname == null)
   {
    throw new argumentnullexception(nameof(propertyname));
   }
 
 
 
   this.funcget = creategetvaluedeleagte(declaretype, propertyname);
  }
 
 
  //代碼核心部分
     private static func<object, object> creategetvaluedeleagte(type declaretype, string propertyname)
  {
   // (object instance) => (object)((declaringtype)instance).propertyname
 
       var param_instance = expression.parameter(typeof(object));
   var body_objtotype = expression.convert(param_instance, declaretype);
   var body_gettypeproperty = expression.property(body_objtotype, propertyname);
   var body_return = expression.convert(body_gettypeproperty, typeof(object));
   return expression.lambda<func<object, object>>(body_return, param_instance).compile();
  }
 
  public object invoke(object instance)
  {
   return this.funcget?.invoke(instance);
  }
 }
 
 
  public class propertysetter
 {
  private readonly action<object, object> setfunc;
 
  public propertysetter(propertyinfo property)
  {
   if (property == null)
 
   {
    throw new argumentnullexception(nameof(property));
   }
   this.setfunc = createsetvaluedelagate(property);
  }
 
 
 
  private static action<object, object> createsetvaluedelagate(propertyinfo property)
  {
   // (object instance, object value) =>
   //  ((instancetype)instance).set_xxx((propertytype)value)
 
   //聲明方法需要的參數(shù)
   var param_instance = expression.parameter(typeof(object));
   var param_value = expression.parameter(typeof(object));
 
   var body_instance = expression.convert(param_instance, property.declaringtype);
   var body_value = expression.convert(param_value, property.propertytype);
   var body_call = expression.call(body_instance, property.getsetmethod(), body_value);
 
   return expression.lambda<action<object, object>>(body_call, param_instance, param_value).compile();
  }
 
  public void invoke(object instance, object value)
  {
   this.setfunc?.invoke(instance, value);
  }
 }

在將代碼應(yīng)用到實例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
dog dog = new dog();
propertyinfo propertyinfo = dog.gettype().getproperty(nameof(dog.name));
 
//反射操作
propertyinfo.setvalue(dog, "wlj");
string result = propertyinfo.getvalue(dog) as string;
console.writeline(result);
 
//表達(dá)式樹的操作
property property = new property(propertyinfo);
property.setvalue(dog, "wlj2");
string result2 = propertyinfo.getvalue(dog) as string;
console.writeline(result2);

發(fā)現(xiàn)其實現(xiàn)的目的與反射一致,但效率卻有明顯的提高。

以下測試以下他們兩之間的效率。測試代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
student student = new student();
propertyinfo propertyinfo = student.gettype().getproperty(nameof(student.name));
property expproperty = new property(propertyinfo);
 
int32 loopcount = 1000000;
codetimer.initialize(); //測試環(huán)境初始化
 
//下面該方法個執(zhí)行1000000次
 
codetimer.time("基礎(chǔ)反射", loopcount, () => {
 propertyinfo.setvalue(student, "fode",null);
});
codetimer.time("lambda表達(dá)式樹", loopcount, () => {
 expproperty.setvalue(student, "fode");
});
codetimer.time("直接賦值", loopcount, () => {
 student.name = "fode";
});
console.readkey();

其.net4.0環(huán)境下運(yùn)行結(jié)果如下:

利用lambda表達(dá)式樹優(yōu)化反射詳解

.net core環(huán)境下運(yùn)行結(jié)果:

利用lambda表達(dá)式樹優(yōu)化反射詳解

從以上結(jié)果可以知道,迭代同樣的次數(shù)反射需要183ms,而用表達(dá)式只要34ms,直接賦值需要7ms,在效率上,使用表達(dá)式這種方法有顯著的提高,您可以看到使用此技術(shù)可以完全避免使用反射時的性能損失。反射之所以效率有點低主要取決于其加載的時候時在運(yùn)行期下,而表達(dá)式則在編譯期,下篇有空將會介紹用emit技術(shù)優(yōu)化反射,會比表達(dá)式略快一點。

注:對于常用對象的屬性,最好將其緩存起來,這樣效率會更高。。

代碼下載

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對服務(wù)器之家的支持。

原文鏈接:https://www.cnblogs.com/fode/p/10079630.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 日本日韩中文字幕 | 最新高清无码专区 | 一本久久a久久精品亚洲 | 欧美日韩免费 | 欧美日本精品 | 亚洲精品视频区 | 成人免费xxx在线观看 | 精品久久亚洲 | 久久久久久亚洲av毛片大全 | 一区欧美 | 羞羞网址| 中文在线一区 | 国产一区二区精品在线观看 | 久久国产亚洲视频 | 日韩成人在线视频 | 欧美日韩中文字幕 | 日韩看片 | 欧美日韩精品一区二区三区四区 | 日韩精品在线播放 | 亚洲天堂av影院 | 国产欧美久久久久久 | 国产欧美中文字幕 | 国产日韩精品一区二区 | 一级黄色大片在线观看 | 精品黑人一区二区三区久久 | av官网在线 | 狠狠狠狠狠狠 | www.亚洲精品 | 日韩中文字幕在线观看视频 | 午夜天堂| 免费高清黄色 | 日本一区二区不卡在线观看 | а_天堂中文最新版地址 | 精品国产乱码久久久久久牛牛 | 中文字幕超清在线免费 | 国产精品99久久久久久动医院 | 91精品国产91久久久 | 久热免费在线观看 | 91av视频免费在线观看 | 草久久| 免费在线看污视频 |