背景:
IL編程在普通的程序員的代碼里幾乎不會出現(xiàn),但從Json.net、Dapper、
Asp.net等等開源項目都體現(xiàn)出了IL編程的重要性。
在IL編程的時候,上百行甚至上千行的IL代碼實在讓人頭大,調(diào)試不方便不說,
IL編程的邏輯也是不同于以往的編程。
為了簡化操作,優(yōu)化IL編程邏輯,設(shè)計了這個庫,取名為Natasha.
簡介:
類庫名稱:Natasha (娜塔莎)(原型蘇聯(lián)紅軍第25步兵師的中尉柳德米拉·帕夫利琴科
,一名出色的女狙擊手)
開源協(xié)議:MPL2.0
版 ? ?本:2016
作 ? ?者:LanX
感 ? ?謝:Xue 和 Denni 在測試以及審查代碼上的支持
地 址:https://github.com/NMSLanX/Natasha
類庫功能:
用前科普
動態(tài)方法IL環(huán)境:
我們創(chuàng)建動態(tài)方法時需要DynamicMethod對象創(chuàng)建ILGenerator實例來操作動態(tài)方法。?
比如 :?
ilA = methodA.GetILGenerator();?
ilB = methodB.GetILGenerator();?
當你用ilA來寫IL代碼的時候,不能用ilB來參與methodA的創(chuàng)建過程。?
也就是ilA產(chǎn)生的臨時變量不能用在ilB中,ilA與ilB是相互隔離的。?
我們在自定義類的時候也會有新的il產(chǎn)生,在設(shè)置屬性的get/set方法的時候也會有新的il產(chǎn)生。?
這里還涉及到在動態(tài)方法中創(chuàng)建動態(tài)方法,所以需要保證il的工作環(huán)境相對是隔離的。?
因此設(shè)計了ThreadCache緩存類來設(shè)置和獲取不同環(huán)境的IL或者action。?
EVar提供了普通變量的操作, EClass提供了類和結(jié)構(gòu)體的操作,EArray提供了數(shù)組的操作這三個主要的操作類都有共同的基類ILGeneratorBase,初始化時會從ThreadCache中取IL.
類的入棧過程
this.Age = 1:
this.Show():
this指針入棧:
在IL編程中:
因此引出初始化類的幾個初始化方法:?
private EModel(Type type, Action action): base(action, type){}?
private EModel(LocalBuilder builder, Type type): base(builder, type) {}?
private EModel(int parameterIndex, Type type): base(parameterIndex, type){}
不管上面三種你選擇了哪一種,this入棧都是由以下的接口來完成的。?
還有ILoadInstance接口:?
void Load(); //不是結(jié)構(gòu)體或者結(jié)構(gòu)體作為值類型填充時,入棧?
void LoadAddress(); //如果是結(jié)構(gòu)體得加載地址?
注:實際封裝要比這三種多,詳情請看工程里的例子
LocalBuilder是臨時變量,用Ldloc代碼來調(diào)用;
ParameterIndex指定參數(shù)索引,用Ldarg等IL代碼來調(diào)用;
委托就是委托,可能委托中的代碼比前兩種更復(fù)雜;
委托形式
外面的LocalBuilder
參數(shù)形式
將this入棧。
調(diào)用show的methodinfo
將this入棧。
將1入棧。
填充fieldinfo 或者 propertyinfo。
使用方法
//動態(tài)創(chuàng)建Action委托
Delegate newMethod0 = EHandler.CreateMethod<ENull>
((il)=>{ }).Compile(); //動態(tài)創(chuàng)建Action<string,int>委托Delegate newMethod1 = EHandler.CreateMethod<string,int,ENull>((il)=>{ }).Compile(); //動態(tài)創(chuàng)建Func<string>委托Delegate newMethod2 = EHandler.CreateMethod<string>((il) => { }).Compile(); //動態(tài)創(chuàng)建Func<string,TestClass>委托Delegate newMethod3 = EHandler.CreateMethod<string, TestClass>((il) =>{ }).Compile(); //動態(tài)創(chuàng)建Action委托
Delegate newMethod = EHandler.CreateMethod<ENull>
((il) => { ? ? ?//創(chuàng)建沒有臨時變量的普通入棧變量(沒有臨時變量,所以自加操作沒有意義) ? ? ?EVar intHandler = 1; ? ? ?//創(chuàng)建函數(shù)操作句柄 ? ? ?EMethod method = typeof(Console); ? ? ?//輸出intHandler的時候,讓變量做加法運算。 ? ? ?method.ExecuteMethod<int>("WriteLine", intHandler + 665); ? ? ?//結(jié)果:666; }).Compile();((Action)newMethod)(); //動態(tài)創(chuàng)建Action委托Delegate newMethod1 = EHandler.CreateMethod<ENull>((il) => { ? ? ? //創(chuàng)建有臨時變量的普通入棧變量(自加操作可以被自身儲存) 也就是說可以使用store存儲函數(shù) ? ? ? //int i = 664; ? ? ? EVar intHandler = EVar.CreateVarFromObject(664); ? ? ? //i++; ? ? ? intHandler++; ? ? ? //i=i+1; ? ? ? intHandler.Store(intHandler + 1); ? ? ? //創(chuàng)建函數(shù)操作句柄 ? ? ? EMethod method = typeof(Console); ? ? ? //輸出intHandler ? ? ? method.ExecuteMethod<int>("WriteLine", intHandler); ? ? ? //結(jié)果:666 }).Compile();((Action)newMethod1)(); //動態(tài)創(chuàng)建Action委托
Delegate newMethod = EHandler.CreateMethod<ENull>
((il) => { ? ?EModel model = null; ? ?//測試類的字段 ? ?//model = EModel.CreateModel<DocumentClassFieldTest>(); ? ?//測試類的屬性 ? ?//model = EModel.CreateModel<DocumentClassPropertyTest>(); ? ?//測試結(jié)構(gòu)體的字段 ? ?model = EModel.CreateModel<StructField>(); ? ?//測試結(jié)構(gòu)體的屬性 ? ?// model = EModel.CreateModel<DocumentStructPropertyTest>(); ? ?model.Set("PublicName", "This is Public-Name"); ? ?model.Set("PrivateName", "This is Private-Name"); ? ?model.Set("PublicAge", 666); ? ?model.Set("PrivateAge", 666); ? ?EMethod method = typeof(Console); ? ?method.ExecuteMethod<string>("WriteLine", model.Load("PrivateName")); ? ?method.ExecuteMethod<string>("WriteLine", model.Load("PublicName")); ? ?method.ExecuteMethod<int>("WriteLine", model.Load("PublicAge")); ? ?method.ExecuteMethod<int>("WriteLine", model.Load("PrivateAge")); }).Compile();((Action)newMethod)(); string[] ? ? ? ?strArray ? ?=
new string[
5];
StructField[] ? structArray =
new StructField[
5];
DocumentEnum[] ?enumArray ? =
new DocumentEnum[
5];
for (int i =
0; i < strArray.Length; i +=
1)
{strArray[i] = i.ToString();enumArray[i] = DocumentEnum.ID;structArray[i] =
new StructField() { PublicAge = i };
}
//string數(shù)組遍歷輸出
Delegate newMethod = EHandler.CreateMethod<ENull>
((il) => { ? ?EMethod method = typeof(Console); ? ?//從運行時獲取數(shù)組并入棧到IL層臨時變量 ? ?EArray stringArrayModel = strArray; ? ?//遍歷數(shù)組 ? ?ELoop.For(stringArrayModel, (currentElement) => ? ?{ ? ? ? ?method.ExecuteMethod<string>("WriteLine", currentElement); ? ?}); }).Compile();((Action)newMethod)(); //自定義數(shù)組Delegate newMethod = EHandler.CreateMethod<ENull>((il) => { ? ?//創(chuàng)建長度為10的int類型數(shù)組 ? ?EArray arrayModel = EArray.CreateArraySpecifiedLength<int>(10); ? ?//索引為5,6,7處填充數(shù)據(jù)6 ? ?arrayModel.StoreArray(5, 6); ? ?arrayModel.StoreArray(6, 6); ? ?arrayModel.StoreArray(7, 6); ? ?//遍歷輸出 ? ?ELoop.For(0, 10, 1, arrayModel, (currentElement) => ? ?{ ? ? ? ?method.ExecuteMethod<int>("WriteLine", currentElement); ? ?}); }).Compile();((Action)newMethod)(); //結(jié)構(gòu)體數(shù)組遍歷輸出Delegate newMethod = EHandler.CreateMethod<ENull>((il) => { ? ?//從運行時獲取數(shù)組并入棧到IL層臨時變量 或者EArray structArrayModel = structArray ? ?EArray structArrayModel = EArray.CreateArrayFromRuntimeArray(structArray); ? ?//遍歷輸出元素的PublicAge字段 ? ?ELoop.For(structArrayModel, (currentElement) => ? ?{ ? ? ? ?EModel model = EModel.CreateModelFromAction(currentElement, typeof(StructField)); ? ? ? ?model.LField("PublicAge"); ? ? ? ?method.ExecuteMethod<int>("WriteLine"); ? ?}); }).Compile();((Action)newMethod)(); //結(jié)構(gòu)體數(shù)組遍歷輸出Delegate newMethod = EHandler.CreateMethod<ENull>((il) => { ? ?EArray enumArrayModel = EArray.CreateArrayFromRuntimeArray(enumArray); ? ?ELoop.For(enumArrayModel, (currentElement) => ? ?{ ? ? ? ?//使用action方式來加載當前元素 ? ? ? ?EModel model = EModel.CreateModelFromAction( ? ? ? ? ? ?currentElement, ? ? ? ? ? ?typeof(DocumentEnum) ? ? ? ?); ? ? ? ?model.Load(); ? ? ? ?//加載之后裝箱 ? ? ? ?EPacket.Packet(typeof(DocumentEnum)); ? ? ? ?//用object參數(shù)的方式輸出 ? ? ? ?method.ExecuteMethod<object>("WriteLine"); ? ?}); }).Compile();((Action)newMethod)(); TestClass t =
new TestClass();t.Field =
10;t.Property =
20;Delegate showResult = EHandler.CreateMethod<ENull>
((il) => { ? ?EMethod method = typeof(Console); ? ?EVar emit_A = EVar.CreateWithoutTempVar(10); ? ?EVar emit_B = EVar.CreateVarFromObject(20); ? ?EModel model = EModel.CreateModelFromObject(t); ? ?EJudge.If(emit_A == model.DLoad("Field").Model)(() => ? ?{ ? ? ? ?method.ExecuteMethod<int>("WriteLine", 10); ? ?}).ElseIf(emit_A > emit_B)(() => ? ?{ ? ? ? ?method.ExecuteMethod<int>("WriteLine", emit_A); ? ?}).Else(() => ? ?{ ? ? ? ?method.ExecuteMethod<int>("WriteLine", emit_B); ? ?}); Delegate showResult = EHandler.CreateMethod<ENull>
((il) => { ? ?EMethod method = typeof(Console); ? ?EVar emit_A = EVar.CreateWithoutTempVar(16); ? ?EVar emit_B = EVar.CreateVarFromObject(20); ? ?ELoop.While(emit_A < emit_B)(() => ? ?{ ? ? ? ?method.ExecuteMethod<int>("WriteLine", emit_B); ? ? ? ?emit_B--; ? ?}); ? ?TestClass t = new TestClass() { Field = 10 }; ? ?EModel model = EModel.CreateModelFromObject(t); ? ?ELoop.While(model.DLoad("Field").Model < emit_B)(() => ? ?{ ? ? ? ?//Console.WriteLine(model.field); ? ? ?
?//這里需要傳遞委托,不傳遞委托則返回的是model類型而不是int類型 ? ? ? ?method.ExecuteMethod<int>( ? ? ? ? ?
? ?"WriteLine", ? ? ? ? ? ?model.DLoad("Field").DelayAction ? ? ? ?); ? ? ? ?//model.Field++ ? ? ? ?model.DLoad("Field").Model++; ? ?}); ? ?ELoop.While(model.DLoad("Field").Model != 25)(() => ? ?{ ? ? ? ?method.ExecuteMethod<int>( ? ? ? ? ? ?"WriteLine", ? ? ? ? ? ?model.DLoad("Property").DelayAction ? ? ? ?); ? ? ? ?model.DLoad("Property").Model++; ? ?}); }).Compile();((Action)showResult)(); ClassBuilder builder = ClassBuilder.CreateModel(
"Hello");
builder.CreateDefaultConstructor();
builder.CreateField<string>(
"Age", FieldAttributes.Public);
builder.CreateProperty<string>(
"Name");
builder.CreateMethod<ENull>
("Show", MethodAttributes.Public, (classModel) => { ? ?classModel.SField("Age", "This is Age."); ? ?classModel.SProperty("Name", "This is name."); ? ?classModel.LPropertyValue("Name"); ? ?classModel.ilHandler.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); ? ?classModel.ilHandler.Emit(OpCodes.Ret); ? ?//下一版酌情對Method創(chuàng)建做優(yōu)化 });builder.EndBuilder(); //使用自定義類Delegate ShowDelegate = EHandler.CreateMethod<ENull>((il) => { ? ?ClassHandler Model = ClassHandler.CreateInstance("Hello"); ? ?Model.EMethod("Show"); ? ?Model.LField("Age"); ? ?Model.ilHandler.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); }).Compile();((Action)ShowDelegate)(); #region 迭代器屬性和方法(不支持)public int Length
{ ? ?
get; ? ?
set;
}
#endregion#region 迭代器屬性和方法(支持)public LocalBuilder TempEnumerator
{ ? ?
get; ? ?
set;
}
public MethodInfo MoveNext
{ ? ?
get; ? ?
set;
}
public MethodInfo Current
{ ? ?
get; ? ?
set;
}
public MethodInfo Dispose
{ ? ?
get; ? ?
set;
}
public void LoadCurrentElement(LocalBuilder currentBuilder)
{ilHandler.Emit(OpCodes.Ldloca, TempEnumerator);ilHandler.Emit(OpCodes.Call, Current);
}
public void Initialize()
{ ? ?
if (TempEnumerator ==
null){TempEnumerator = ilHandler.DeclareLocal(
typeof(List<T>.Enumerator));MethodInfo GetEnumerator =TypeHandler.GetMethod( ? ? ? ? ? ?
"GetEnumerator",
new Type[
0]);LoadAddress();ilHandler.Emit(OpCodes.Callvirt, GetEnumerator);ilHandler.Emit(OpCodes.Stloc, TempEnumerator);MoveNext =
typeof(List<T>.Enumerator).GetMethod( ? ? ? ? ? ?
"MoveNext",
new Type[
0]);Current =
typeof(List<T>.Enumerator).GetProperty(
"Current").GetGetMethod(
true);Dispose =
typeof(List<T>.Enumerator).GetMethod(
"Dispose",
new Type[
0]);}
}
#endregio
愿景
1、希望大家以平和的心態(tài)去對待菜鳥開源庫的事情;
2、Json.net 不也是人寫出來的嗎?Dapper是憑空產(chǎn)生的嗎?希望大家發(fā)揮自己的創(chuàng)造力
,共創(chuàng)輝煌?
計劃
1、本庫采用MPL2.0開源協(xié)議、召集小伙伴繼續(xù)完善下去,歡迎加入到開發(fā)隊伍中,
QQ群號:573026640;
2、Natasha每年更一次正式版,版本號用去年的年號;
吐槽
對于說我重復(fù)造輪子的人我沒什么好說的,誰造誰知道;
對于說我裝B的人我想說一下:你猜錯了,我想裝C,裝完C還想裝D;這個庫2016年開始封裝,中間推翻了兩版,重構(gòu)十次以上,精神分裂、懵逼N次,
懷疑人生1次,求小伙伴們一起參與到建設(shè)中來!為什么拿Natasha來命名這個庫,因為她墓志銘上有這兩句話:痛苦如此持久,像蝸牛充滿耐心地移動;
快樂如此短暫,像兔子的尾巴掠過秋天的草原;(跟開發(fā)過程相符)
結(jié)尾
我相信,這行沒有學(xué)習(xí)能力是走不遠的。
我也相信,沒有創(chuàng)造力是看不清未來的。
愿這個庫能給您的項目帶來方便,給創(chuàng)作帶來便利與靈感。?
希望.NET在接下來的發(fā)展中能吸引更多的創(chuàng)造者,讓.NET世界百花齊放。
原文地址:http://blog.csdn.net/lanx_fly/article/details/59617050
.NET社區(qū)新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關(guān)注
總結(jié)
以上是生活随笔為你收集整理的开源库 Natasha2016 ,让IL编程跑起来的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。