clr via c# 程序集加载和反射集(一)
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 in dlls let asb = assembly.loadfrom(file) from t in asb.exportedtypes where t.ispublic && t.isclass && (typeof(iaddin).gettypeinfo().isassignablefrom(t.gettypeinfo())) select t).tolist();//获取有该接口的类. types.foreach(//创建类的实列并且工作. x => { iaddin t = (iaddin)activator.createinstance(x); display(0,t.dosomething(10)); }); }