1,程式集載入 弱的程式集可以載入強簽名的程式集,但是不可相反.否則引用會報錯!(但是,反射是沒問題的) //獲取當前類的Assembly Assembly.GetEntryAssembly() //通過Load方法載入程式集 Assembly.Load //通過LoadFrom載入指定路徑名的程式 ...
1,程式集載入---弱的程式集可以載入強簽名的程式集,但是不可相反.否則引用會報錯!(但是,反射是沒問題的)
//獲取當前類的Assembly Assembly.GetEntryAssembly() //通過Load方法載入程式集 Assembly.Load //通過LoadFrom載入指定路徑名的程式集--可以時url對象. Assembly LoadFrom(string path) //只是反射,並確保程式集中的數據不被執行. ReflectionOnlyLoadFrom() ReflectionOnlyLoad(string assembly string)
2,發現程式集中定義的類型
class ReflectionRef { public static void Demo1() { string AssemblyName = "s7.net, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d5812d469e84c693, processorArchitecture=MSIL"; Assembly a = Assembly.Load(AssemblyName); Display(0, "{0}'s types:",a.FullName); a.ExportedTypes.ToList().ForEach(x => Display(2, "t's FullName is {0}", x.FullName)); Console.WriteLine(); a = Assembly.GetEntryAssembly(); Display(0, "{0}'s types:", a.FullName); a.ExportedTypes.ToList().ForEach(x => Display(2, "t's FullName is {0}", x.FullName)); } private static void Display(int indent,string Format,params object[] obj) { Console.Write(new string(' ', indent * 2)); Console.WriteLine(Format, obj); } }
結果:
s7.net, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d5812d469e84c693's types:
t's FullName is S7.Net.TcpClientMixins
t's FullName is S7.Net.Conversion
2,類型對象的準確含義.
//通過實列獲得類型 obj.GetType(); //通過Type類的靜態函數GetType() public static Type GetType (string typeName);//必須是FullName //是否拋出異常和忽略大小寫. public static Type GetType (string typeName, bool throwOnError, bool ignoreCase); //
參數
- typeName
- String
要獲取的類型的程式集限定名稱。 請參閱 AssemblyQualifiedName。 如果該類型位於當前正在執行的程式集中或者 Mscorlib.dll 中,則提供由命名空間限定的類型名稱就足夠了。
System.TypeInfo提供了實列成員DeclaredNestedTypes和GetDeclaredNestedType定義了類中嵌套的類型.
System.Reflection.Assembly 類型提供了實列成員
GetType \\string,輸入的類型的全名
DefinedTypes \\ 返回所有定義的類型的TypeInfo.
public virtual System.Collections.Generic.IEnumerable<System.Reflection.TypeInfo> DefinedTypes { get; }
ExportedTypes\\返回所有定義的公共類型
public virtual System.Collections.Generic.IEnumerable<Type> ExportedTypes { get; }
type對象是輕量級引用,需要更多的瞭解類型本身,必須獲取一個TypeInfo對象
TypeInfo ti = typeof(ReflectionRef).GetTypeInfo();
- IsPublic
- IsSealed
- IsAbstract
- IsClass
- IsValueType
- 另一些參數返回:
- Assembly
- AssemblyQulifiedName
- FullName
- Module
3,通過反射構建派生類的層次結構
- 批量載入程式集---註意,載入程式集的四個要素
{Name{0},PublicKeyToken={1},version={2},Culture={3}}
private static void LoadAssemblies() { String[] assemblies = { "System, PublicKeyToken={0}", "System.Core, PublicKeyToken={0}", "System.Data, PublicKeyToken={0}", "System.Design, PublicKeyToken={1}", "System.DirectoryServices, PublicKeyToken={1}", "System.Drawing, PublicKeyToken={1}", "System.Drawing.Design, PublicKeyToken={1}", "System.Management, PublicKeyToken={1}", "System.Messaging, PublicKeyToken={1}", "System.Runtime.Remoting, PublicKeyToken={0}", "System.Security, PublicKeyToken={1}", "System.ServiceProcess, PublicKeyToken={1}", "System.Web, PublicKeyToken={1}", "System.Web.RegularExpressions, PublicKeyToken={1}", "System.Web.Services, PublicKeyToken={1}", "System.Windows.Forms, PublicKeyToken={0}", "System.Xml, PublicKeyToken={0}", }; String EcmaPublicKeyToken = "b77a5c561934e089"; String MSPublicKeyToken = "b03f5f7f11d50a3a"; // Get the version of the assembly containing System.Object // We'll assume the same version for all the other assemblies Version version = typeof(System.Object).Assembly.GetName().Version; // Explicitly load the assemblies that we want to reflect over foreach (String a in assemblies) { String AssemblyIdentity = String.Format(a, EcmaPublicKeyToken, MSPublicKeyToken) + ", Culture=neutral, Version=" + version; Assembly.Load(AssemblyIdentity);//在AppDomain中載入程式集 } }
- 找到所有的派生自MemberInfo的類型
public static void Demo2() { Assembly[] oldAssembly = AppDomain.CurrentDomain.GetAssemblies();//未載入程式集時的app Domain中的程式集 LoadAssemblies();//載入程式集 var newAssemblyName = (from a in AppDomain.CurrentDomain.GetAssemblies()//獲取在原程式集中的程式集 where Array.IndexOf(oldAssembly, a) >= 0 orderby a.FullName select a.FullName).ToArray(); Array.ForEach<string>(newAssemblyName, x => Display(3, x));//列印原程式集 Console.WriteLine("Compare Assemblys end"); var allTypes = (from a in AppDomain.CurrentDomain.GetAssemblies() from t in a.ExportedTypes where typeof(MemberInfo).GetTypeInfo().IsAssignableFrom(t.GetTypeInfo())//獲取所有派生自Exception的類型. orderby t.Name select t).ToArray(); Display(0, WalkInheritanceHierachy(new StringBuilder(), 0, typeof(MemberInfo), allTypes).ToString());//迭代列印這些類型. }
- 迭代查找派生關係
private static StringBuilder WalkInheritanceHierachy(StringBuilder sb,int indent,Type baseType,IEnumerable<Type> allTypes)//迭代列印函數 { string spaces = new string(' ', indent * 3);//首碼空格 sb.AppendLine(spaces + baseType.FullName);//添加基類的全名,新一行. foreach(var t in allTypes) { if (t.GetTypeInfo().BaseType != baseType) continue;//如果這個類不是另一個類的基列,繼續. WalkInheritanceHierachy(sb, indent + 1, t, allTypes);//如果找到某個類是派生類,則將這個類作為基類,去查找新的派生類. } return sb; }
- 結果:
System.Reflection.MemberInfo
System.Reflection.EventInfo
System.Runtime.InteropServices.ComAwareEventInfo
System.Reflection.FieldInfo
System.Reflection.Emit.FieldBuilder
System.Reflection.MethodBase
System.Reflection.ConstructorInfo
System.Reflection.Emit.ConstructorBuilder
System.Reflection.MethodInfo
System.Reflection.Emit.DynamicMethod
System.Reflection.Emit.MethodBuilder
System.Reflection.PropertyInfo
System.Reflection.Emit.PropertyBuilder
System.Type
System.Reflection.TypeInfo
System.Reflection.Emit.EnumBuilder
System.Reflection.Emit.GenericTypeParameterBuilder
System.Reflection.Emit.TypeBuilder
System.Reflection.TypeDelegator
4,BindingFlags
欄位
CreateInstance | 512 |
創建類的實列,Invoke類的實列調用類的構造器時使用.
|
DeclaredOnly | 2 |
指定當前類上面聲明的成員 |
Default | 0 |
指定未定義任何綁定標誌。 |
ExactBinding | 65536 |
未知... |
FlattenHierarchy | 64 |
指定應返回層次結構往上的公共成員和受保護靜態成員。. 靜態成員包括欄位、方法、事件和屬性。. 不支持嵌套類型。 |
GetField | 1024 |
指定應返回指定欄位的值。此標誌會傳遞給 |
GetProperty | 4096 |
指定應返回指定屬性的值。此標誌會傳遞給 |
IgnoreCase | 1 |
指定在綁定時不應考慮成員名稱的大小寫。 |
IgnoreReturn | 16777216 |
在 COM 互操作中用於指定可以忽略成員的返回值。 |
Instance | 4 |
指定實例成員要包括在搜索中。 |
InvokeMethod | 256 |
指定要調用的方法。非構造器 此標誌會傳遞給 |
NonPublic | 32 |
指定非公共成員要包括在搜索中。 |
OptionalParamBinding | 262144 |
返回其參數計數與提供的參數數量匹配的成員集。 此綁定標誌用於參數具有預設值的方法和使用變數參數 (varargs)
的方法。此標誌只應與 InvokeMember(String, BindingFlags, Binder, Object,
Object[], ParameterModifier[], CultureInfo, String[]) 結合使用。 |
Public | 16 |
指定公共成員要包括在搜索中。 |
PutDispProperty | 16384 |
指定應調用 COM 對象上的 |
PutRefDispProperty | 32768 |
指定應調用 COM 對象上的 |
SetField | 2048 |
指定應設置指定欄位的值。 |
SetProperty | 8192 |
指定應設置指定屬性的值。 |
Static | 8 |
指定靜態成員要包括在搜索中。 |
SuppressChangeType | 131072 |
未實現。 |
public class BindingFlagsRef { public static void Go() { // BindingFlags.InvokeMethod // Call a static method. Type t = typeof(TestClass); Console.WriteLine(); Console.WriteLine("Invoking a static method."); Console.WriteLine("-------------------------"); t.InvokeMember("SayHello", BindingFlags.InvokeMethod | BindingFlags.Public |//調用類的靜態方法.註意Binder=null,Target=null BindingFlags.Static, null, null, new object[] { }); // BindingFlags.InvokeMethod // Call an instance method. TestClass c = new TestClass(); Console.WriteLine(); Console.WriteLine("Invoking an instance method."); Console.WriteLine("----------------------------"); c.GetType().InvokeMember("AddUp", BindingFlags.InvokeMethod, null, c, new object[] { });//調用實列的方法,註意,Target=c; c.GetType().InvokeMember("AddUp", BindingFlags.InvokeMethod, null, c, new object[] { });//調用實列的方法,註意,Target=c; // BindingFlags.InvokeMethod // Call a method with parameters. object[] args = new object[] { 100.09, 184.45 }; object result; Console.WriteLine(); Console.WriteLine("Invoking a method with parameters."); Console.WriteLine("---------------------------------"); result = t.InvokeMember("ComputeSum", BindingFlags.InvokeMethod , null, null, args);//調用帶參數的方法. Console.WriteLine("{0} + {1} = {2}", args[0], args[1], result); // BindingFlags.GetField, SetField Console.WriteLine(); Console.WriteLine("Invoking a field (getting and setting.)"); Console.WriteLine("--------------------------------------"); // Get a field value. result = t.InvokeMember("Name", BindingFlags.GetField, null, c, new object[] { });//獲取和設定欄位. Console.WriteLine("Name == {0}", result); // Set a field. t.InvokeMember("Name", BindingFlags.SetField, null, c, new object[] { "NewName" }); result = t.InvokeMember("Name", BindingFlags.GetField, null, c, new object[] { }); Console.WriteLine("Name == {0}", result); Console.WriteLine(); Console.WriteLine("Invoking an indexed property (getting and setting.)"); Console.WriteLine("--------------------------------------------------"); // BindingFlags.GetProperty // Get an indexed property value. int index = 3; result = t.InvokeMember("Item", BindingFlags.GetProperty, null, c, new object[] { index });//獲取索引器的值. Console.WriteLine("Item[{0}] == {1}", index, result); // BindingFlags.SetProperty // Set an indexed property value. index = 3; t.InvokeMember("Item", BindingFlags.SetProperty, null, c, new object[] { index, "NewValue" });//設定索引器的值. result = t.InvokeMember("Item", BindingFlags.GetProperty, null, c, new object[] { index }); Console.WriteLine("Item[{0}] == {1}", index, result); Console.WriteLine(); Console.WriteLine("Getting a field or property."); Console.WriteLine("----------------------------"); // BindingFlags.GetField // Get a field or property. result = t.InvokeMember("Name", BindingFlags.GetField | BindingFlags.GetProperty, null, c, new object[] { }); Console.WriteLine("Name == {0}", result);//獲取屬性或者欄位的對象. // BindingFlags.GetProperty result = t.InvokeMember("Value", BindingFlags.GetField | BindingFlags.GetProperty, null, c, new object[] { });//獲取屬性或者欄位的對象. Console.WriteLine("Value == {0}", result); Console.WriteLine(); Console.WriteLine("Invoking a method with named parameters."); Console.WriteLine("---------------------------------------"); // BindingFlags.InvokeMethod // Call a method using named parameters. object[] argValues = new object[] { "Mouse", "Micky" }; String[] argNames = new String[] { "lastName", "firstName" }; t.InvokeMember("PrintName", BindingFlags.InvokeMethod, null, null, argValues, null, null,//指定Named類型的方法. argNames); Console.WriteLine(); Console.WriteLine("Invoking a default member of a type."); Console.WriteLine("------------------------------------"); // BindingFlags.Default // Call the default member of a type. Type t3 = typeof(TestClass2); t3.InvokeMember("", BindingFlags.InvokeMethod | BindingFlags.Default, null, new TestClass2(), new object[] { });//利用特性MemberDefault,和反射配合指定使用方法.當前是Print. // BindingFlags.Static, NonPublic, and Public // Invoking a member with ref parameters. Console.WriteLine(); Console.WriteLine("Invoking a method with ref parameters."); Console.WriteLine("--------------------------------------"); MethodInfo m = t.GetMethod("Swap"); args = new object[2]; args[0] = 1; args[1] = 2; //m.Invoke(new TestClass(), args);//和調用有參的形式一樣,這是新的辦法 t.InvokeMember("Swap", BindingFlags.InvokeMethod, null, new TestClass(), args);//這是通過type來調用. Console.WriteLine("{0}, {1}", args[0], args[1]); // BindingFlags.CreateInstance // Creating an instance with a parameterless constructor. Console.WriteLine(); Console.WriteLine("Creating an instance with a parameterless constructor."); Console.WriteLine("------------------------------------------------------"); object cobj = t.InvokeMember("TestClass", BindingFlags.Public |//註意3個BindingFlags的應用. BindingFlags.Instance | BindingFlags.CreateInstance, null, null, new object[] { });//創建類的實列的另外一個辦法. Console.WriteLine("Instance of {0} created.", cobj.GetType().Name); // Creating an instance with a constructor that has parameters. Console.WriteLine(); Console.WriteLine("Creating an instance with a constructor that has parameters."); Console.WriteLine("------------------------------------------------------------"); cobj = t.InvokeMember("TestClass", BindingFlags.Public |//創建有參的構造器,並且返回實列. BindingFlags.Instance | BindingFlags.CreateInstance, null, null, new object[] { "Hello, World!" }); Console.WriteLine("Instance of {0} created with initial value '{1}'.", cobj.GetType().Name, cobj.GetType().InvokeMember("Name", BindingFlags.GetField, null, cobj, null)); // BindingFlags.DeclaredOnly Console.WriteLine(); Console.WriteLine("DeclaredOnly instance members."); Console.WriteLine("------------------------------"); System.Reflection.MemberInfo[] memInfo = t.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Instance |//考慮在本類中創建(非繼承,實列,公共)的成員集合. BindingFlags.Public); for (int i = 0; i < memInfo.Length; i++) { Console.WriteLine(memInfo[i].Name); } // BindingFlags.IgnoreCase Console.WriteLine(); Console.WriteLine("Using IgnoreCase and invoking the PrintName method."); Console.WriteLine("---------------------------------------------------"); t.InvokeMember("printname", BindingFlags.IgnoreCase | BindingFlags.Static |//忽略大小寫 BindingFlags.Public | BindingFlags.InvokeMethod, null, null, new object[] {"Brad","Smith"}); // BindingFlags.FlattenHierarchy Console.WriteLine(); Console.WriteLine("Using FlattenHierarchy to get inherited static protected and public members."); Console.WriteLine("----------------------------------------------------------------------------"); FieldInfo[] finfos = typeof(MostDerived).GetFields(BindingFlags.NonPublic | BindingFlags.Public |//NoPublic是Protected對象. BindingFlags.Static | BindingFlags.FlattenHierarchy);//返回受保護靜態成員. foreach (FieldInfo finfo in finfos) { Console.WriteLine("{0} defined in {1}.", finfo.Name, finfo.DeclaringType.Name);//DeclaringType...成員所定義的Type } Console.WriteLine(); Console.WriteLine("Without FlattenHierarchy."); Console.WriteLine("-------------------------"); finfos = typeof(MostDerived).GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static); foreach (FieldInfo finfo in finfos) { Console.WriteLine("{0} defined in {1}.", finfo.Name, finfo.DeclaringType.Name); } } } public class TestClass { public String Name; private Object[] values = new Object[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; public Object this[int index] { get { return values[index]; } set { values[index] = value; } } public Object Value { get { return "the value"; } } public TestClass() : this("initialName") { } public TestClass(string initName) { Name = initName; } int methodCalled = 0; public static void SayHello() { Console.WriteLine("Hello"); } public void AddUp() { methodCalled++; Console.WriteLine("AddUp Called {0} times", methodCalled); } public static double ComputeSum(double d1, double d2) { return d1 + d2; } public static void PrintName(String firstName, String lastName) { Console.WriteLine("{0},{1}", lastName, firstName); } public void PrintTime() { Console.WriteLine(DateTime.Now); } public void Swap(ref int a, ref int b) { int x = a; a = b; b = x; } } [DefaultMemberAttribute("PrintTime")] public class TestClass2 { public void PrintTime() { Console.WriteLine(DateTime.Now); } } public class Base { static int BaseOnlyPrivate = 0; protected static int BaseOnly = 0; } public class Derived : Base { public static int DerivedOnly = 0; } public class MostDerived : Derived { }
上面的列子枚舉了差不多的一些反射調用一個類中的方法或者欄位或者其他的一些用法
5,Binder-----從候選者列表中選擇一個成員,並執行實參類型到形參類型的類型轉換,需要實現派生
Binder用來自定義選擇匹配的方法,欄位等...一般不用,或者使用Type.DefaultBinder使用.
6,構造類的實列
通過反射構造類的實列常用方法:
public static void CallCreateObjectByReflection() { //方法1,使用createInstance--type方法. Type t = typeof(TestClass); TestClass t1 = (TestClass)Activator.CreateInstance(t, new object[] { }); Display(0, t1.Name); //方法2,使用程式集的方法,第一個參數可以是null,當前程式集,或者是Assembly.GetEnterAssembly.ToString(),返回程式集的全名. var t2 = (TestClass)Activator.CreateInstance(null, typeof(TestClass).FullName).Unwrap(); Display(0, Assembly.GetEntryAssembly().ToString()); Display(0, t2.Name); //方法3,使用CreateInstanceFrom生成. var path = Assembly.GetEntryAssembly().CodeBase; var t3 = (TestClass)Activator.CreateComInstanceFrom(path, typeof(TestClass).FullName).Unwrap(); Display(0, "path is {0},type is {1}", path, t3); //方法4,使用AppDomain的CreateInstance;註意,如果是另外的appDomain則需要類型是MarshalRefObject的派生類,或者可序列化對象. AppDomain ad0 = AppDomain.CreateDomain("Ad0"); var t4=AppDomain.CurrentDomain.CreateInstanceFromAndUnwrap(path, typeof(TestClass).FullName); Display(0, "path is {0},type is {1}", path, t4); //方法5,使用InVokeMember調用構造器. var t5 = (TestClass)t.InvokeMember("", BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance, null, null, null); Display(0, t5.Name); //方法6,使用ConstructorInfo,其實類似上面的 ConstructorInfo ci = t.GetConstructor(new Type[] { typeof(string) }); var t6=(TestClass)ci.Invoke(new object[] { "new Constructor" }); Display(0, t6.Name); //方法7,數組類型創建實列 Array t7 = Array.CreateInstance(t, 10); for(int i=0;i<t7.Length;i++) { t7.SetValue(new TestClass(i.ToString()), i); } int count=0; Array.ForEach<TestClass>((TestClass[])t7, x => Display(count++, x.Name)); //方法7_1,另外一個方法創建數組的實列. Type t71 = t.MakeArrayType(); var t72 =(TestClass[]) Activator.CreateInstance(t71, new object[] { 10 }); Display(0, t72.Length.ToString()); //方法8,委托類型創建實列 MethodInfo mi = t.GetMethod("AddUp"); var t8 = new TestClass(); Delegate d = Delegate.CreateDelegate(typeof(Action), t8, mi); d.DynamicInvoke(); d.DynamicInvoke(); //方法9,構造泛型實列 Type openType = typeof(Dictionary<,>);//首先創建openType Type closeType = openType.MakeGenericType(typeof(string),typeof(string));//創建封閉Type Type ListOpenType = typeof(List<>);//創建新的OpenType Type ListCloseType = ListOpenType.MakeGenericType(closeType);//創建複合的封閉對象 object o = Activator.CreateInstance(ListCloseType);//創建類型對象的實列. Display(0, o.ToString()); } }
7,設計支持載入項的程式.
在使用過程中發現System.IO.FileLoadException錯誤,的原因為:
- 如果某個類是強名稱,那麼所有它引用的類也必須都是強名稱.
我因為忘記給HostSDK進行強名稱設定,所以出錯.HostSDK進行之後,AddIn也要進行.
1,設計介面類:
//HostSDK.cs using System; namespace Winteliect.HostSDK { public interface IAddin { string DoSomeThing(Int32 x); } }
2,設計介面實現類
//AddInTypes.cs using System; using Winteliect.HostSDK; namespace AddInTypes { public sealed class AddIn_A:IAddin { public AddIn_A(){} public string DoSomeThing(Int32 x) { return "AddIn_A:"+x.ToString(); } } public sealed class AddIn_B:IAddin { public AddIn_B(){} public string DoSomeThing(Int32 x) { return "AddIn_B:"+(2*x).ToString(); } } }
3,進行編譯dll
- sn -k host.snk
- csc.exe /out:HostSDK.dll /t:library /keyfile:host.snk HostSDK.cs---生成HostSDK.dll
- csc.exe /out:AddInTypes.dll /t:library /r:HostSDK.dll /keyfile:host.snk AddInTypes.cs---生成AddInTypes.dll
4,在程式中使用
public static void DynamicLoadDemo() { string path = Assembly.GetExecutingAssembly().Location;//獲取.exe的詳細路徑 string AddInDir = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);//獲取.exe的目錄.../Debug var dlls = Directory.EnumerateFiles(AddInDir, "*.dll");// var types = (from file