反射和激活类型
获取类型
1.GetType()和typeof都可以获取类型,GetType是在运行时,而typeof是在编译时
2.可以在获取一个基础类型后再构造其他类型
Type simpleArray = typeof(int).MakeArrayType();
Console.WriteLine(simpleArray == typeof(int[]));
先获取int,再获取int类型的数组和直接获取int[]类型是一样的。
3.GetElementType可以返回数组元素的类型
4.获取嵌套类型GetNestedTypes()
5.类型具有Namespace,Name,Fullname。一般Fullname=Name+Namespace
6.泛型类型带有'后缀,数字表示有几个参数
7.Type具有BaseType属性,可以查找基类
8.GetInterfaces方法会返回类型实现的接口
9.和is等价的动态运算符 IsInstanceOfType,IsAssignableFrom
10.从类型创建实例:
int i = (int)Activator.CreateInstance(typeof(int));
ConstructorInfo ci = typeof(X).GetConstructor(new[] { typeof(string) });
object foo = ci.Invoke(new object[] { null });
11.Type可以表示泛型类型,也可以表示封闭类型,MakeGenericType可以将泛型转为封闭类型。GetGenericTypeDefinition可以实现翻转。
反射并调用成员
1.GetMembers可以返回类型的成员
2.每一个属性、字段和方法的类型的MemberInfo
3.GetMembers会返回所有类型的成员,可以传参MemberTypes枚举来限定返回的成员类型
4.还有专门的返回固定类型的方法,GetMethods,GetFields。。。
成员类型
1.MemberInfo是所有类型信息的抽象基类
2.不同的类型可以由不同的MemberInfo对应的子类去接受
3.*Info实例都会在第一次使用时由反射API缓存,增加性能
4.一个属性有get和set方法,可以在获取属性后获取它的get和set方法
5.获取属性后就可以实现动态绑定了
object s = "Hello";
PropertyInfo prop = s.GetType().GetProperty("Length");
int length = (int)prop.GetValue(s, null);
6.方法的调用
Type type = typeof(string);
Type[] par = { typeof(int),typeof(int) };
MethodInfo method = type.GetMethod("Substring", par);
object[] arguement = { 2,1 };
object returnValue = method.Invoke("stamp", arguement);
Console.WriteLine(returnValue);
对于方法重载,要注意参数的设置
7.检索调用泛型方法,需要遍历所有泛型方法,找到符合的那个方法再调用。用表达式树则可以省略很多
8.动态调用为几微秒,用实例委托来代替可以降至几纳秒。
MethodInfo m = typeof(string).GetMethod("Trim", new Type[0]);
var trim = (StringToString)Delegate.CreateDelegate(typeof(StringToString), m);
原理就是让反射只发生一次
9.BindingFlags可以改变枚举,返回非公有成员
10.使用泛型方法时先要给泛型确定类型
MethodInfo m = typeof(Program).GetMethod("Echo");
MethodInfo m2 = m.MakeGenericMethod(typeof(int));
Console.WriteLine(m2.Invoke(null,new object[] { 3}));
11.调用未知类型的泛型接口成员
通过多次判断类型(用is),来对不同的类型做出不同的特殊处理
反射程序集
1.返回命名空间下的类型
Type t = Assembly.GetExecutingAssembly().GetType("Net.Program");
2.从类型获得程序集
var a = typeof(Test).GetType().Assembly.GetType();
3.加载一个程序集
Assembly a = Assembly.LoadFrom(@"E:\obj\Debug\Framework.exe");
4.由于可以获得一个程序集的所有类型,所以可以将一些类型专门构成一个程序集。像Asp.Net Core中的Service和其实现类就可以用这种方法
使用特性
CLR允许使用特性将额外的元数据追加到类型、成员和程序集上
特性基础
1.C#三类特性:位映射特性、自定义特性、伪自定义特性
2.位映射特性:public、abstract。。。
3.自定义特性:自己定义的特性
4.伪自定义特性:系统带的特性,会由内部转为位映射特性
AttributeUsage特性
1.AttributeUsage可以定义特性的特性。
2.AllowMultiple:能否在目标上运用多次
3.Inherited:能否被子类继承
4.ValidOn:目标集合
定义自定义特性
public class Person
{
[Custom1(Num =4,Name ="hi")]
public string Name { get; set; }
private int Age;
}
[AttributeUsage(AttributeTargets.Property)]
public class Custom1Attribute : Attribute
{
public int Num { get; set; }
public string Name { get; set; }
}
AttributeUsage限定属性,特性可以给属性传参,也可以用构造函数来传参
在运行时检索特性
自定义特性用CustomAttribute,GetCustomAttribute来获取
动态生成代码
1.DynamicMethod可以在运行时生成方法
2.OpCodes对每一个IL操作码都有一个对应的静态只读字段
MethodInfo c = typeof(Program).GetMethod("HelloWorld", BindingFlags.Static | BindingFlags.NonPublic);
b.Emit(OpCodes.Call,c);
b.Emit(OpCodes.Ret);
a.Invoke(null, null);
3.评估栈就是参数的临时存放区
4.将整数加载至评估栈
MethodInfo c = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int)});
b.Emit(OpCodes.Ldc_I4,123);
b.Emit(OpCodes.Call, c);
b.Emit(OpCodes.Ret);
5.Add将一个数字弹出,计算后在压入
MethodInfo c = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int)});
b.Emit(OpCodes.Ldc_I4,123);
b.Emit(OpCodes.Ldc_I4, 123);
b.Emit(OpCodes.Add);
b.Emit(OpCodes.Call, c);
b.Emit(OpCodes.Ret);
6.向动态方法传参
var a = new DynamicMethod("Foo", typeof(int),
new Type[] { typeof(int),typeof(int)}, typeof(Program));
var b = a.GetILGenerator();
b.Emit(OpCodes.Ldarg_0);
b.Emit(OpCodes.Ldarg_1);
b.Emit(OpCodes.Add);
b.Emit(OpCodes.Ret);
int result = (int)a.Invoke(null, new object[] { 3,4});
Console.WriteLine(result);
7.生成局部变量
ILGenerator.DeclareLocal
var dynMeth = new DynamicMethod("Test", null, null, typeof(void));
var gen = dynMeth.GetILGenerator();
LocalBuilder localX = gen.DeclareLocal(typeof(int));
LocalBuilder localY = gen.DeclareLocal(typeof(int));
gen.Emit(OpCodes.Ldc_I4, 6); //将6压入栈
gen.Emit(OpCodes.Stloc, localX); //将栈中的值给localX
gen.Emit(OpCodes.Ldc_I4, 7); //将7压入栈
gen.Emit(OpCodes.Stloc, localY); //将栈中的值给localY
gen.Emit(OpCodes.Ldloc, localX); //将localX压入栈
gen.Emit(OpCodes.Ldloc, localY); //将localY压入栈
gen.Emit(OpCodes.Mul); //计算乘积
gen.Emit(OpCodes.Stloc, localX); //将乘积的值传给localX
gen.EmitWriteLine(localX);
gen.Emit(OpCodes.Ret);
dynMeth.Invoke(null, null);
8.分支
ILGenerator.DefineLabel
ILGenerator.MarkLabel
Br(无分支条件),Brture(true则分支),Blt(第一个值小于第二个值则分支)
var dynMeth = new DynamicMethod("Test", null, null, typeof(void));
var gen = dynMeth.GetILGenerator();
Label startLoop = gen.DefineLabel();
Label endLoop = gen.DefineLabel();
LocalBuilder x = gen.DeclareLocal(typeof(int));
gen.Emit(OpCodes.Ldc_I4, 6); //将6压入栈
gen.Emit(OpCodes.Stloc, x); //将栈中的值给X
gen.MarkLabel(startLoop); //开启一个分支
gen.Emit(OpCodes.Ldc_I4, 10);
gen.Emit(OpCodes.Ldloc, x);
gen.Emit(OpCodes.Blt, endLoop); //跳到结束标记
gen.EmitWriteLine(x);
gen.Emit(OpCodes.Ldloc, x);
gen.Emit(OpCodes.Ldc_I4, 1);
gen.Emit(OpCodes.Add);
gen.Emit(OpCodes.Stloc, x);
gen.Emit(OpCodes.Br, startLoop);
gen.MarkLabel(endLoop); //分支结束标记
gen.Emit(OpCodes.Ret);
dynMeth.Invoke(null, null);
9.实例化对象与调用实例方法
ILGenerator.Newobj
OpCodes.Call:调用静态方法和值类型的实例方法
OpCodes.Callvirt:调用引用类型的实例方法
var dynMeth = new DynamicMethod("Test", null, null, typeof(void));
var gen = dynMeth.GetILGenerator();
ConstructorInfo ci = typeof(StringBuilder).GetConstructor(new Type[0]);
gen.Emit(OpCodes.Newobj, ci);
gen.Emit(OpCodes.Callvirt, typeof(StringBuilder).GetProperty("MaxCapacity").GetGetMethod());
gen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] { typeof(int) }));
gen.Emit(OpCodes.Ret);
dynMeth.Invoke(null, null);
var dynMeth = new DynamicMethod("Test", null, null, typeof(void));
var gen = dynMeth.GetILGenerator();
ConstructorInfo ci = typeof(StringBuilder).GetConstructor(new[] { typeof(string),typeof(int)});
gen.Emit(OpCodes.Ldstr, "Hello");
gen.Emit(OpCodes.Ldc_I4, 1000);
gen.Emit(OpCodes.Newobj, ci);
Type[] strT = { typeof(string) };
gen.Emit(OpCodes.Ldstr, ", world");
gen.Emit(OpCodes.Call, typeof(StringBuilder).GetMethod("Append", strT));
gen.Emit(OpCodes.Callvirt, typeof(object).GetMethod("ToString"));
gen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", strT));
gen.Emit(OpCodes.Ret);
dynMeth.Invoke(null, null);
10.异常处理
ILGenerator.BeginExceptionBlock
ILGenerator.BeginCatchBlock
ILGenerator.BeginFinalBlock
ILGenerator.EndExceptionBlock
var dynMeth = new DynamicMethod("Test", null, null, typeof(void));
var gen = dynMeth.GetILGenerator();
MethodInfo emi = typeof(NotSupportedException).GetProperty("Message").GetGetMethod();
MethodInfo cmi = typeof(Console).GetMethod("WriteLine",new [] { typeof(object)});
gen.BeginExceptionBlock();
ConstructorInfo ci = typeof(NotSupportedException).GetConstructor(new Type[0]);
gen.Emit(OpCodes.Newobj, ci);
gen.Emit(OpCodes.Throw);
gen.BeginCatchBlock(typeof(NotSupportedException));
gen.Emit(OpCodes.Callvirt, emi);
gen.Emit(OpCodes.Call, cmi);
gen.BeginFinallyBlock();
gen.EmitWriteLine("Finally");
gen.EndExceptionBlock();
gen.Emit(OpCodes.Ret);
dynMeth.Invoke(null, null);
生成程序集和类型
保存生成的程序集
有些方法.Net Framework和.Net Core是不一样的
AppDomain domain = AppDomain.CurrentDomain;
AssemblyName name = new AssemblyName("MyEmissions");
name.Version = new Version(2, 13, 0, 1);
AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly(name,
AssemblyBuilderAccess.RunAndSave);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule",
"MyEmissions.dll");
TypeBuilder tb = moduleBuilder.DefineType("Widget", TypeAttributes.Public);
MethodBuilder methodBuilder = tb.DefineMethod("SayHello", MethodAttributes.Public, null, null);
ILGenerator gen = methodBuilder.GetILGenerator();
gen.EmitWriteLine("Hello World!");
gen.Emit(OpCodes.Ret);
tb.CreateType(); //必须要加
assemblyBuilder.Save("MyEmissions.dll");
2.在CreateType之前,类型属于未创建状态
3.动态生成的程序集可以保存成为文件,该文件可以是dll或者exe,一旦保存成文件后,就可以以静态的方式调用
生成类型成员
1.生成方法
MethodBuilder mb = tb.DefineMethod("SquareRoot",
MethodAttributes.Static | MethodAttributes.Public,
CallingConventions.Standard, typeof(double), new[] { typeof(double) });
ILGenerator gen2 = mb.GetILGenerator();
gen2.Emit(OpCodes.Ldarg_0);
gen2.Emit(OpCodes.Call,typeof(Math).GetMethod("Sqrt"));
gen2.Emit(OpCodes.Ret);
Type realType = tb.CreateType();
double x = (double)tb.GetMethod("SquareRoot").Invoke(null, new object[] { 10.0 });
Console.WriteLine(x);
2.生成字段和属性
TypeBuilder tb = moduleBuilder.DefineType("Widget", TypeAttributes.Public);
FieldBuilder field = tb.DefineField("length", typeof(int), FieldAttributes.Private);
FieldBuilder field1 = tb.DefineField("_text", typeof(string), FieldAttributes.Private);
PropertyBuilder pb = tb.DefineProperty("Text", PropertyAttributes.None, typeof(string), new Type[0]);
MethodBuilder getter = tb.DefineMethod("get_text", MethodAttributes.Public | MethodAttributes.SpecialName,
typeof(string), new Type[0]);
ILGenerator gen = getter.GetILGenerator();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldfld, field);
gen.Emit(OpCodes.Ret);
MethodBuilder setter = tb.DefineMethod("set_text", MethodAttributes.Assembly | MethodAttributes.SpecialName,
null, new[] { typeof(string)});
ILGenerator gen2 = setter.GetILGenerator();
gen2.Emit(OpCodes.Ldarg_0);
gen2.Emit(OpCodes.Ldarg_1);
gen2.Emit(OpCodes.Stfld, field);
gen2.Emit(OpCodes.Ret);
pb.SetGetMethod(getter);
pb.SetSetMethod(setter);
Type t = tb.CreateType();
object o = Activator.CreateInstance(t);
t.GetProperty("Text").SetValue(o, "Good", new object[0]);
string text = (string)t.GetProperty("Text").GetValue(o, null);
Console.WriteLine(text);
3.生成构造器
TypeBuilder tb = moduleBuilder.DefineType("Widget", TypeAttributes.Public);
FieldBuilder field = tb.DefineField("_capacity", typeof(int), FieldAttributes.Private);
ConstructorBuilder c = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard
, new Type[0]);
ILGenerator gen = c.GetILGenerator();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldc_I4,4000);
gen.Emit(OpCodes.Stfld, field);
gen.Emit(OpCodes.Ret);