利用dot Net技術中反射及代碼發送的
動態退化或同步化接口封裝
1 技術背景
在“動態”這個詞到處用的時代,怎樣能夠讓程序真正的動態起來。
在Java的結構中我們看到了一個java.lang.reflect包,開始讓程序能夠了解程序的結構。然後作爲Java的好徒弟dot Net框架中System.Reflection命名空間看到了 AssemblyBuilder,ModuleBuilder,TypeBuilder及其它*Builder,而程序能夠構造程序結構。我們進入了真正的動態運用的時代。
回想一下,這是多麼令人震驚的功能啊!讓我們運行動態生成的代碼吧。如果你運行的不是原本硬盤上載入的代碼,那是多大的飛躍啊!
1.1 反射
反射是dot Net框架中的面向對象技術中的一個極爲重要的部分。它由System.Type類和System.Reflection命名空間及其子空間中的所有類完成。在所有類的根類Object的實例方法GetType()可以得到描述實例的類信息的Type類實例。
反射的功能使得程序可以瞭解自身結構的手段,除此還可以提供動態構造程序集(Assembly),模塊(Module),類(Type)結構的途徑,使得原本僵死的程序有了活力。反射使得程序可以訪問程序結構,構造程序結構。反射(reflection也稱retrospection)的還可翻譯爲“自省”或“反省” 。
1.2 代碼發送
代碼發送就是運行時向方法構造器發送操作碼和參數,使得最終實現動態生成類。然後就可以使用需要的代碼結構進行操作。
反射發送是一種“發送”操作碼的強大技術。雖然今天的編譯器速度很快,內存和處理器的速度也足夠,但是在必須的時候能夠觸及這麼核心底層的部分,確實是一件令人欣慰的事情。
2 退化與同步化理論
2.1 退化
由面向對象的繼承性多態性使得編程模型呈現出一個擴展的發散的結構,在許多接口的應用中將會只用到部分的功能(這裏一般指方法(Method),dot Net中還包括屬性(Property)和事件(Event))。那麼對於其他的部分只好在實現時放出異常或不作任何操作。如此便出現了退化,也就是一部分功能的退化。舉例來講:
l Sysetm.Collections.IList的C#語言聲明:
public interface IList : ICollection, IEnumerable
{
int Add(object value);
void Clear();
bool Contains(object value);
int IndexOf(object value);
void Insert(int index, object value);
void Remove(object value);
void RemoveAt(int index);
bool IsFixedSize { get; }
bool IsReadOnly { get; }
object this[int index] { get; set; }
}
要實現上面的IList接口的只讀(Read Only)封裝是,要求在一個只讀的派生類中退化Add, Clear, Insert, Remove, RemoveAt, this[]{set;}這些方法或屬性,並且IsReadOnly返回常量true。 然而如此只是文檔的規則不能保證一個返回IsReadOnly 爲true的實例必然做好了ReadOnly退化。
這樣的退化僅僅是文檔內的約定,而更應該程序約束。在後面的動態封裝中就介紹了標準的退化封裝的手段。
2.2 同步化
實現同步化封裝一般對要封裝的類或接口的所有方法重寫,重寫模版如下:
public override ReturnType A_Method()
{
lock (this._syncRoot)
return this._target.A_Method();
}
在直接調用前後,要進行同步化操作進入對象和退出對象。這樣實現的類就成爲原有類或接口的同步化封裝。由於在多線程的應用中經常用到同步化封裝,這裏不贅述其應用了。
3 dot Net 框架中的退化與同步化封裝實現
ReadOnlyList類是Sysetm.Collections.ArrayList類的私有嵌套類,是對IList接口的ReadOnly退化封裝。
SyncList類是Sysetm.Collections.ArrayList類的私有嵌套類,是對IList接口的同步化封裝。
通過的兩個靜態方法可以獲得相應的封裝實例,下面是相關的部分C#聲明:
l ArrayList類的摘要聲明:
public class ArrayList : IList, ICollection, IEnumerable, ICloneable
{
……
private class ReadOnlyList : IList
{……}
private class SyncIList : IList
{……}
public static IList ReadOnly(IList list)
{
if (list == null)
throw new ArgumentNullException("list");
return new ArrayList. ReadOnlyList(list);
}
public static IList Synchronized(IList list)
{
if (list == null)
throw new ArgumentNullException("list");
return new ArrayList.SyncIList(list);
}
}
l ReadOnlyList類的摘要聲明:
private class ReadOnlyList : IList
{
internal ReadOnlyList(IList l)
{
this._list = l;
}
private IList _list;
//退化方法實現
public virtual int Add(object obj)
{
throw new NotSupportedException(Environment.GetResourceString("NotSupported"));
}
……
//非退化方法實現
public virtual bool Contains(object obj)
{
return this._list.Contains(obj);
}
……
public virtual bool IsReadOnly
{
get
{
return true;
}
}
……
}
退化的方法例如Add,放出異常。非退化的方法例如Contains,直接調用。只有IsReadOnly特殊處理返回true。
l SyncList類的摘要聲明:
private class SyncIList : IList
{
internal SyncIList(IList list)
{
this._list = list;
this._root = list.SyncRoot;
}
private IList _list;
private object _root;
public virtual int Add(object value)
{
lock (this._root)
return this._list.Add(value);
}
……
public virtual bool IsSynchronized
{
get
{
return true;
}
}
……
public virtual object SyncRoot
{
get
{
return this._root;
}
}
}
同步化處理所有方法例如Add。只有IsSynchronized特殊處理返回true,SyncRoot特殊處理返回初始化時輸入的異步根。
4 動態封裝模型
4.1 原有模式的弊端
由上面dot Net框架裏的實現方法可以看到,針對需要封裝的接口要寫出對應的類實現。也就是說每次要按照退化或同步化的模式編寫代碼。可以看到代碼的信息量如此之小,可以說,編寫這樣的代碼是程序員的悲哀。
程序員的第一原則,所有重複的操作要讓程序去做。如果程序員手動去做這件事不僅是折磨程序員,而且是摧毀了程序的嚴謹結構。這樣,差錯容易出現,程序可讀性降低,代碼冗餘繁雜。
於是按照上面的模式而生成的類應該由程序實現,有人會用文本處理自動生成代碼,但這不是我們的最終目的。我們要的只是一個繼承對應接口的類結構,而且對具體的類名稱不敏感,但我們需要他全局唯一,從而在下次引用方便。所以如果靠生成代碼,那麼他就不能作爲通用的標準在標準庫中創建實例。
客觀的講,任何地方聲明的接口,都應有其唯一對應的封裝實現。而不是由不同的程序員去一次次的編寫不同的實現,這樣也不能給出標準封裝檢查。
4.2 理想的封裝模型
l 全局封裝器Boxer類的C#語言封裝部分聲明:
public sealed class Boxer
{
public static object Degenerate(object target, Type interfaceType, IDegenerateProvider dp);
public static object Degenerate(object target, Type interfaceType, Type degenerateAttributeType);
public static object Synchronize(object target, Type interfaceType);
public static object Synchronize(object target, Type interfaceType, object syncRoot);
……
}
我們可以通過前兩個的靜態方法獲得任意接口的指定退化方式的退化實例。也可通過後兩個靜態方法獲得任意接口的異步封裝。
l IDegenerateProvider接口的C#語言完整聲明:
public interface IDegenerateProvider
{
DegenerateTargets NeedDegenerate(EventInfo evn);
bool NeedDegenerate(MethodInfo method);
DegenerateTargets NeedDegenerate(PropertyInfo property);
}
提供判斷是否退化的判斷方法的接口。退化需要提供這樣的供應器實例。
l Boxer類的C#語言封裝檢查部分聲明:
public sealed class Boxer
{
public static bool IsDegenerated(object target, IDegenerateProvider dp);
public static bool IsDegenerated(object target, Type degenerateAttributeType);
public static bool IsDegenerated(object target, Type interfaceType, IDegenerateProvider dp);
public static bool IsDegenerated(object target, Type interfaceType, Type degenerateAttributeType);
public static bool IsSynchronized(object target);
public static bool IsSynchronized(object target, object syncRoot);
public static bool IsSynchronized(object target, Type interfaceType);
public static bool IsSynchronized(object target, Type interfaceType, object syncRoot);
……
}
l DegenerateAttribute屬性類和DegenerateTargets枚舉類的C#語言完整聲明:
public abstract class DegenerateAttribute : Attribute
{
protected DegenerateAttribute(): this(DegenerateTargets.All){}
protected DegenerateAttribute(DegenerateTargets targets)
{
this._targets = targets;
}
public DegenerateTargets Targets { get{ return this._targets;} }
private readonly DegenerateTargets _targets;
public static IDegenerateProvider GetDegenerateProvider(Type attributeType);
internal class DegenerateProvider : IDegenerateProvider
{
public DegenerateProvider(Type attributeType);
……
}
}
[Serializable, Flags]
public enum DegenerateTargets
{
Method = 0x01,
Getter = 0x02,
Setter = 0x04
Adder = 0x08,
Remover = 0x10,
Event = Adder | Remover ,
Property = Getter | Setter,
All = Method | Event | Property,
None = 0,
}
DegenerateAttribute爲所有退化自定義屬性提供抽象基類,其派生類用於指定退化的方法(Method)或屬性(Property)的具體讀寫器或事件(Event)的具體Adder或Remover。給出他的類信息可由其靜態函數和嵌套類可以得到相應的IDegenerateProvider的實例。
l 理想的適應ReadOnly退化包裝的Sysetm.Collections.IList的C#語言完整聲明,ReadOnly退化屬性類:ReadOnlyDegenerateAttribute的C#語言完整聲明:
public interface IList : ICollection, IEnumerable
{
[ReadOnlyDegenerate]
int Add(object value);
[ReadOnlyDegenerate]
void Clear();
bool Contains(object value);
int IndexOf(object value);
[ReadOnlyDegenerate]
void Insert(int index, object value);
[ReadOnlyDegenerate]
void Remove(object value);
[ReadOnlyDegenerate]
void RemoveAt(int index);
[ReadOnlyDegenerate (DegenerateTagets.Setter)]
object this[int index] { get; set; }
}
[Serializable, AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event)]
public sealed class ReadOnlyDegenerateAttribute : DegenerateAttribute
{
public ReadOnlyAttribute();
public ReadOnlyAttribute(DegenerateTargets targets);
}
4.3 模型的優勢
如果僅僅對某個接口人工代碼實現指定退化的類。那麼這個接口的繼承接口的退化工作將會是由許多重複的,這樣的人工代碼實現將是無效率的。那麼這個退化的信息應該標識到接口聲明裏,那麼這樣的信息不僅是給這個接口與這個退化的,還將提供給繼承接口去完成這樣的退化。
所有的接口都客觀存在其退化和同步化接口封裝,那麼這樣的封裝類不應該由程序員來實現,而應該有程序動態生成。
5 如何發送代碼實現動態封裝類
在退化供應器的指導下我們退化的工作知道那些功能因該退化那些應該調用,而同步化的封裝是出人意料的簡單,每個方法的實現都有同種模式來實現。因爲本文重在提供動態封裝的模式。而發送代碼的工作牽扯到微軟中間語言(MSIL),而這只是技術實現,當然我們在其它支持反射及代碼發送的平臺下一樣可以實現它。而且應該的是標準庫中所應該提供的部分。
下面是同步化接口封裝的C#語言實現的關鍵部分:
private static void ImplementMethodSyncInvoke(TypeBuilder tb, MethodInfo mi, FieldBuilder fb, FieldBuilder rfb)
{
Type[] typeArray1 = Boxer.ParamsTypes(mi.GetParameters());
MethodBuilder builder1 = tb.DefineMethod(mi.Name, Boxer. InterfaceMethodAttributes, mi.ReturnType, typeArray1);
ILGenerator generator1 = builder1.GetILGenerator();
generator1.DeclareLocal(typeof(object));
//爲返回值申請本地內存空間
if (mi.ReturnType != typeof(void))
generator1.DeclareLocal(mi.ReturnType);
//載入同步根實例
generator1.Emit(OpCodes.Ldarg_0);
generator1.Emit(OpCodes.Ldfld, rfb);
generator1.Emit(OpCodes.Dup);
generator1.Emit(OpCodes.Stloc_0);
//進入同步化區
generator1.Emit(OpCodes.Call, Boxer.ThreadEnterMethod);
//爲保證不會因爲調用過程的異常造成程序跳出,而形成死鎖,需要try{}finally{}處理退出同步化區
//try{
generator1.BeginExceptionBlock();
generator1.Emit(OpCodes.Ldarg_0);
//爲調用載入對象
generator1.Emit(OpCodes.Ldfld, fb);
//載入所有參數
int num1 = typeArray1.Length;
if (num1 > 0)
{
generator1.Emit(OpCodes.Ldarg_1);
if (num1 > 1)
{
generator1.Emit(OpCodes.Ldarg_2);
if (num1 > 2)
{
generator1.Emit(OpCodes.Ldarg_3);
for (int num2 = 4; num2 <= num1; num2++)
generator1.Emit(OpCodes.Ldarg_S, (byte) num2);
}
}
}
//調用
generator1.Emit(OpCodes.Callvirt, mi);
//存儲返回值
if (mi.ReturnType != typeof(void))
generator1.Emit(OpCodes.Stloc_1);
//}
//finally{
generator1.BeginFinallyBlock();
generator1.Emit(OpCodes.Ldloc_0);
generator1.Emit(OpCodes.Call, Boxer.ThreadExitMethod);
//}
generator1.EndExceptionBlock();
//載入返回值
if (mi.ReturnType != typeof(void))
generator1.Emit(OpCodes.Ldloc_1);
generator1.Emit(OpCodes.Ret);
tb.DefineMethodOverride(builder1, mi);
}
private static void ImplementInterface(TypeBuilder tb, Type interfaceType, FieldBuilder fb, FieldBuilder rfb)
{
//實現Methods
MethodInfo[] infoArray1 = interfaceType.GetMethods();
for (int num1 = 0; num1 < infoArray1.Length; num1++)
{
MethodInfo info1 = infoArray1[num1];
Boxer.ImplementMethodSyncInvoke(tb, info1, fb, rfb);
}
//實現Properties
PropertyInfo[] infoArray2 = interfaceType.GetProperties();
for (int num2 = 0; num2 < infoArray2.Length; num2++)
{
PropertyInfo info2 = infoArray2[num2];
MethodInfo info3 = info2.GetGetMethod(true);
if (info3 != null)
Boxer.ImplementMethodSyncInvoke(tb, info3, fb, rfb);
info3 = info2.GetSetMethod(true);
if (info3 != null)
Boxer.ImplementMethodSyncInvoke(tb, info3, fb, rfb);
}
//實現Events
EventInfo[] infoArray3 = interfaceType.GetEvents();
for (int num3 = 0; num3 < infoArray3.Length; num3++)
{
EventInfo info4 = infoArray3[num3];
MethodInfo info5 = info4.GetAddMethod(true);
if (info5 != null)
Boxer.ImplementMethodSyncInvoke(tb, info5, fb, rfb);
info5 = info4.GetRemoveMethod(true);
if (info5 != null)
Boxer.ImplementMethodSyncInvoke(tb, info5, fb, rfb);
}
}
internal static object InternalSynchronize(object target, Type interfaceType, object syncRoot)
{
object obj1;
lock (Boxer.SynchronizedTable)
{
//找出已經生成的對於動態類的構造函數
ConstructorInfo info1 = (ConstructorInfo) Boxer.SynchronizedTable[interfaceType];
if (info1 == null)
{
Type[] typeArray1 = new Type[2] { interfaceType, typeof(object) } ;
TypeBuilder builder1 = Boxer.BoxerModuleBuilder.DefineType("BoxedClasses.Synchronized" + (++Boxer.SynchronizedCount), TypeAttributes.Public);
builder1.SetCustomAttribute(new CustomAttributeBuilder(Boxer.SynchronizedAttribute.Constructor, new object[0]));
builder1.AddInterfaceImplementation(interfaceType);
//構造字段target
FieldBuilder builder2 = builder1.DefineField(Boxer.FindName(interfaceType, "_target"), interfaceType, Boxer.FieldAttribute);
//構造字段syncroot
FieldBuilder builder3 = builder1.DefineField(Boxer.FindName(interfaceType, "_syncroot"), typeof(object), Boxer.FieldAttribute);
//構造唯一的構造方法
ConstructorBuilder builder4 = builder1.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, typeArray1);
ILGenerator generator1 = builder4.GetILGenerator();
generator1.Emit(OpCodes.Ldarg_0);
generator1.Emit(OpCodes.Call, Boxer.ObjectConstructor);
generator1.Emit(OpCodes.Ldarg_0);
generator1.Emit(OpCodes.Ldarg_1);
generator1.Emit(OpCodes.Stfld, builder2);
generator1.Emit(OpCodes.Ldarg_0);
generator1.Emit(OpCodes.Ldarg_2);
generator1.Emit(OpCodes.Stfld, builder3);
generator1.Emit(OpCodes.Ret);
Boxer.ImplementInterface(builder1, interfaceType, builder2, builder3);
Type[] typeArray3 = interfaceType.GetInterfaces();
for (int num1 = 0; num1 < typeArray3.Length; num1++)
{
Type type1 = typeArray3[num1];
Boxer.ImplementInterface(builder1, type1, builder2, builder3);
}
//將此實例加入全局表,以便後用
Boxer.SynchronizedTable.Add(interfaceType, (info1 = builder1.CreateType().GetConstructor(typeArray1)));
}
object[] objArray1 = new object[2] { target, syncRoot } ;
obj1 = info1.Invoke(objArray1);
}
return obj1;
}
6 新的語法規範
由.NET 2.0 基礎類庫對範型的應用來看,這裏的退化和同步化當然也可以作出新的語法規範方便程序員調用。下面以C#語言爲例介紹新的語法規範。
6.1 同步化
我們可以通過關鍵字synchronize和on來得到對應的同步化的類實例,通過issynchronized得到同步化檢查,例如:
IList list;
object syncRoot;
……
//[] 爲可選部分
IList slist = list synchronize IList [on syncRoot ];
//內部實現=(IList)Boxer.Synchronize(list[, syncRoot]);
bool issync = slist issynchronized IList [on syncRoot];
//內部實現=Boxer.IsSynchronized(slist [, syncRoot]);
6.2 退化
我們可以通過關鍵字degenerate 和on可獲得退化類實例,通過isdegenerated得到同步化檢查,例如:
IList list;
IDegenerateProvider degenerateProvider;
……
IList dlist = list degenerate IList on typeof(ReadOnlyDegenerateAttribute);
//內部實現= (IList)Boxer.Degenerate(list, typeof(ReadOnlyDegenerateAttribute));
IList dlist1 = list degenerate IList on degenerateProvider;
///內部實現= (IList)Boxer.Degenerate(list, degenerateProvider);
Bool isdeg = dlist isdegenerated IList on typeof(ReadOnlyDegenerateAttribute);
//內部實現=(IList)Boxer.IsDegenerated(list, typeof(ReadOnlyDegenerateAttribute));
6.3 無退化接口封裝
我們可以通過關鍵字box可獲得接口封裝實例,通過isboxed得到同步化檢查,例如:
IList list = new ArrayList();
……
IList blist = list box IList;
//內部實現= (IList)Boxer.Degenerate(list, typeof(NonDegenerateAttribute));
Bool isb = blist isboxed IList;
//內部實現=(IList)Boxer.IsDegenerated(list, typeof(NonDegenerateAttribute));