1. What is metadata (the MetaData) and reflection (Reflection)
Under normal circumstances we are in the process of program data read, write, and display operations. But the data is not digital operation of some programs, text, graphics, but the type of information and programs itself.
① metadata containing programs and data type information, which is stored in the program among the set program.
② program at run time, you can view other assemblies or its metadata itself. This behavior is reflected.
2.Type class
BCL Type declares a type (which is an abstract class), to contain the type of characteristics. Use objects of this class allows us to obtain the type of information used by the program.
Because Type is an abstract class, so it can not be instantiated. But at runtime, CLR to create an instance derived from Type (RuntimeType) type. When we want to access these instances, CLR does not return a reference to the derived class but returns a reference to the base class Type.
About Type the following important points:
For each type of program ① need to use, CLR will wear a type of an object Type of this type of information include (say above is true instance of the derived type).
Are linked to two separate object class Type ② procedures used in each type.
③ type regardless of how many instances created, only a Type object is associated with all of these instances. As the following figure shows the same. Create an instance OtherClass OC, and two instances of MyClass and MC2 of mc1, but they correspond, as illustrated in the following there will be only a heap Type of object:
Type a brief look at this type, which you can see some of the following methods and properties.
Official documents more comprehensive Oh: https://docs.microsoft.com/zh-cn/dotnet/api/system.type?view=netframework-4.8
3. Learn how to get a class object Type
Method 1: Method GetType
GetType type object contains a method that can be used to return the Type object reference examples. Because all classes are inherited from the object type, so all classes can call to get the Type GetType type of object. Good description of the following figures, the relationship between a base class and a derived class object
Therefore, the following code, traversing Field derived class to time, to be outputted out of the base class.
//基类 class BaseClass { public int BaseField = 0; } //派生类 class DerivedClass : BaseClass { public int DerivedField = 0; } class Program { static void Main(string[] args) { var bc = new BaseClass(); var dc = new DerivedClass(); BaseClass[] bca = new BaseClass[] { bc, dc }; the foreach ( var V in BCA) { // Get the type of the Type T = v.GetType (); Console.WriteLine ( " Object the Type: {0} " , t.Name); // Get field class FieldInfo [] fi = t.GetFields (); the foreach ( var F in Fi) Console.WriteLine ( " Field,: {0} " , F.Name); Console.WriteLine (); } Console.WriteLine ( " End! "); Console.ReadKey(); } }
result:
Object Type: BaseClass
Field:BaseField
Object Type: DerivedClass
Field:DerivedField
Field:BaseField
End!
Method II: can also acquire a type of the object referenced by Type typeof () method. For example the following code:
Type t = typeof(DerivedClass);
In addition, we can get the type within the assembly according to assembly
// acquired by an assembly type var = Assembly.GetExecutingAssembly the baseType () the GetType ( "TestDemo.BaseClass");. Var = DerivedType Assembly.GetExecutingAssembly () the GetType ( "TestDemo.DerivedClass").;
4. A common operating
Typeof and GetType combined operation, can do many things.
① Gets an array of types
static void Main(string[] args) { var intArray = typeof(int).MakeArrayType(); var int3Array = typeof(int).MakeArrayType(3); Console.WriteLine($"是否是int 数组 intArray == typeof(int[]) :{intArray == typeof(int[]) }"); Console.WriteLine($"是否是int 3维数组 intArray3 == typeof(int[]) :{int3Array == typeof(int[]) }"); Console.WriteLine($"是否是int 3维数组 intArray3 == typeof(int[,,]):{int3Array == typeof(int[,,]) }"); // array element type the Type = elementType is intArray.GetElementType (); the Type elementType2 = int3Array.GetElementType (); Console.WriteLine ($ " {} intArray type element type: elementType is {} " ); Console.WriteLine ($ " {} int3Array type element type: elementType2 {} " ); // dimension of the array acquiring var Rank = int3Array.GetArrayRank (); Console.WriteLine ($ " {} int3Array dimension number type: Rank {} " ); Console .ReadKey (); }
As the above example,
MakeArrayType () can be used to obtain an array type, a parameter is a dimension of the array
GetElementType () can be used to obtain the array element type
GetArrayRank () can get the dimension of the array
② get nested types
public class Class { public class Student { public string Name { get; set; } } } class Program { static void Main(string[] args) { #region 嵌套类型 var classType = typeof(Class); foreach (var t in classType.GetNestedTypes()) { Console.WriteLine($"NestedType ={t}"); // Gets a value that indicates whether declared as public System.Type type. Console.WriteLine ($ " {T}} t.IsPublic access { " ); // Gets a value indicating whether a class by which is nested and declared public. Console.WriteLine ($ " {T}} t.IsNestedPublic access { " ); } the Console.ReadKey (); #endregion } }
Output:
NestedType =TestDemo.Class+Student TestDemo.Class+Student访问 False TestDemo.Class+Student访问 True
③ get the type name
Which has Type NameSpace, Name and FullName property. FullName typically a combination of both. But it does not hold for nested and closed generic type. Refer to the following demo
static void the Main ( String [] args) { #region Gets the name var type = typeof (Class); Console.WriteLine ($ " \ n ------ ------------ general type ------- " ); PrintTypeName (of the type); // nested types Console.WriteLine ($ " \ nested the n-type ------- ------------ ------ " ); the foreach ( var T in type.GetNestedTypes ()) { PrintTypeName (T); } var Type2 = typeof (the Dictionary <,>); // non-closed generic var Type3 = typeof (the Dictionary < String , int >); // closed generic Console.WriteLine ($ " \ n-non-closed pan ------------ type ------------- " ); PrintTypeName (type2); Console.WriteLine ($ " \ the n-closed generic ---- ------------ --------- " ); PrintTypeName (Type3); the Console.ReadKey (); #endregion } Private static void PrintTypeName (the Type T) { Console.WriteLine ($ " NameSpace: t.Namespace {} " ) ; Console.WriteLine($"Name :{t.Name}"); Console.WriteLine($"FullName: {t.FullName}"); }
result:
------------ general types ------------- NameSpace: TestDemo the Name: Class the FullName: TestDemo.Class ------------ nested types ------------- NameSpace: TestDemo the Name: Student the FullName: TestDemo.Class + Student NameSpace: TestDemo the Name: Teacher the FullName: TestDemo.Class + Teacher -------- ---- non-closed generic ------------- NameSpace: System.Collections.Generic the Name: Dictionary` 2 the FullName: System.Collections.Generic.Dictionary` 2 ----- ------- closed generic ------------- NameSpace: System.Collections.Generic the Name: Dictionary` 2 FullName: System.Collections.Generic.Dictionary`2[ [System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089], [System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
④ acquired base class and interface type
var base1 = typeof(System.String).BaseType; var base2 = typeof(System.IO.FileStream).BaseType; var base3 = typeof(DerivedClass).BaseType; Console.WriteLine($"base1 :{base1.Name}"); Console.WriteLine($"base2 :{base2.Name}"); Console.WriteLine($"base3 :{base3.Name}"); foreach (var iType in typeof(Guid).GetInterfaces()) { Console.WriteLine($"iType :{iType.Name}"); }
Output:
BASE1: Object base2: Stream base3: BaseClass type in: IFormattable type in: IComparable type in: IComparable` 1 type in: IEquatable` 1
In addition Type There are two methods:
We determine whether an object is an instance of a type, the statement is often used.
Methods IsInstanceOfType Type in fact, and is equivalent.
baseClassObject new new BaseClass = var (); var = Check1 baseClassObject is BaseClass; var = base3.IsInstanceOfType the check2 (baseClassObject); Console.WriteLine ($ "is determined using the same type is: {check1}"); // results True Console. WriteLine ($ "is the same type used IsInstanceOfType: {check2}"); // True results
The results are returned to True.
There is a IsAssignableFrom, its role is to determine whether the specified instance of the type can be assigned to the current type instance.
var base4 = typeof (BaseClass); // baseClass Examples var baseClassObject new new BaseClass = (); var derivedClassObject new new DerivedClass = (); var = classObject new new Class (); var = checkResult1 base4.IsAssignableFrom (baseClassObject.GetType ()) ; // determines whether BaseClass types can be assigned to BassClass type var checkResult2 = base4.IsAssignableFrom (derivedClassObject.GetType () ); // determines whether DerivedClass types can be assigned to BassClass type var checkResult3 = base4.IsAssignableFrom (classObject.GetType () ) ; // determines whether the type can be allocated to Class BassClass type Console.WriteLine ($ "type is used and the type of receiving IsAssignableFrom consistent: checkResult1 {}"); // True Console.WriteLine ($ "type is used and accepted IsAssignableFrom consistent type: checkResult2 {} "); // True Console.WriteLine ($" same type is used and accepted IsAssignableFrom type: {checkResult3} "); // False
⑤ instantiated type
I. There are two ways of instantiating dynamic type.
A method created by static Activator.CreateInstance () method, it has multiple overloaded functions.
var dateTime1 = (DateTime)Activator.CreateInstance(typeof(DateTime),2019,6,19); var dateTime2 = (DateTime)Activator.CreateInstance(typeof(DateTime), 2019,6,19,10,10,10); Console.WriteLine($"DateTime1: {dateTime1}"); //DateTime1: 2019/6/19 0:00:00 Console.WriteLine($"DateTime2: {dateTime2}"); //DateTime2: 2019/6/19 10:10:10
Generally, we pass parameters as above is a Type and constructor. When the constructor does not exist and it will throw an error.
Method two calls ConstructInfo objects above the Invoke method, ConstructInfo objects are obtained by calling the type (Senior Environmental) GetConstructor method on.
First analysis of the scene, for example, I have a type such as the following:
public class InvokeClass { private string _testString; private long _testInt; public InvokeClass(string abc) { _testString = abc; } public InvokeClass(StringBuilder abc) { _testString = abc.ToString(); } public InvokeClass(string abc,long def) { _testString = abc; _testInt = def; } }
There are two constructors, a type of string is passed, a StringBuilder type is passed, at this time if I go to create an object by way of new and pass the constructor is null, then the following error is reported : Description existence of ambiguity, which means that the corresponding use can not be found to construct.
Similarly, if I use a Activator.CreateInstance to create an object, it will appear the following problem: Can not find the corresponding constructor.
ConstructInfo manner but using the corresponding can specify the constructor. Similarly following code
// constructor parameter to find a string of var = ConstructorInfo typeof (InvokeClass) .GetConstructor (new new [] {typeof (string)}); // use this constructor passing a null argument var obj4 = (InvokeClass) constructorInfo. Invoke (new object [] {null });
You can also combine queries to find the corresponding constructor
//获取所有的构造函数 var constructorInfoArray = typeof(InvokeClass).GetConstructors(); //过滤一次,获取所有两个参数的构造函数 var constructorInfoArray2 = Array.FindAll(constructorInfoArray, x => x.GetParameters().Length == 2); //最后找的第二个参数是long类型的构造函数 var constructorInfo2 = Array.Find(constructorInfoArray2, x => x.GetParameters()[1].ParameterType == typeof(long)); //如果存在,就创建对象 if (constructorInfo2 != null) { var obj5 = (InvokeClass)constructorInfo2.Invoke(new object[] { "abc", 123 }); }
动态构造对象的缺点就是慢,简单对比一下,采用反射和new创建100万个对象,耗时对比还是比较明显的。
var sw = new Stopwatch(); sw.Start(); for (int i = 0; i < 100000; i++) { var obj3 = (InvokeClass)Activator.CreateInstance(typeof(InvokeClass), "abc", 123); } sw.Stop(); Console.WriteLine($"时间:{sw.ElapsedMilliseconds}ms"); var sw2 = new Stopwatch(); sw2.Start(); for (int i = 0; i < 100000; i++) { var obj = new InvokeClass("abc", 123); } sw2.Stop(); Console.WriteLine($"时间:{sw2.ElapsedMilliseconds}ms");
输出:
时间:280ms
时间:1ms
II. 实例化委托
动态创建静态方法和实例方法的委托传入的参数不太一样,使用的是CreateDelegate的重载,可以参考下面的例子
/// <summary> /// 创建指定类型的委托,该委托表示要对指定的类实例调用的指定实例方法。 /// </summary> /// <param name="type">要创建的委托的 System.Type</param> /// <param name="target"> 类实例,对其调用 method</param> /// <param name="method">委托要表示的实例方法的名称</param> /// <returns></returns> public static Delegate CreateDelegate(Type type, object target, string method); /// <summary> /// 创建指定类型的委托,该委托表示指定类的指定静态方法。 /// </summary> /// <param name="type">要创建的委托的 System.Type</param> /// <param name="target"> 表示实现 method 的类的 System.Type</param> /// <param name="method"> 委托要表示的静态方法的名称。</param> /// <returns></returns> public static Delegate CreateDelegate(Type type, Type target, string method);
例如:
class Program { public static int StaticSum(int a, int b) { return a + b; } public int InstanceSum(int a, int b) { return a + b; } //创建一个委托 delegate int delegateOperate(int a, int b); static void Main(string[] args) { #region 实例化委托 //静态方法的委托 Delegate staticD = Delegate.CreateDelegate(typeof(delegateOperate), typeof(Program), "StaticSum"); //实例方法的委托 Delegate instanceD = Delegate.CreateDelegate(typeof(delegateOperate), new Program(), "InstanceSum"); Console.WriteLine($"staticD:{staticD.DynamicInvoke(1,2)}"); Console.WriteLine($"instanceD:{instanceD.DynamicInvoke(10,20)}"); #endregion Console.ReadKey(); } }
III.范型的实例化
泛型分为封闭型和未封闭型,对于封闭类型的泛型是可以通过反射进行实例化的,而未封闭的泛型不能实例化。如下图所示:
封闭式的泛型和未绑定的泛型是可以相互转换的。
①未绑定的泛型可以通过 MakeGenericType 变成封闭的
②封闭的可以通过GetGenericTypeDefinition 获取未绑定的类型。
class Program { static void Main(string[] args) { Type closed = typeof(List<int>); Type unBound = typeof(List<>); //转换 var newClosed = unBound.MakeGenericType(typeof(int)); var newUnBound = closed.GetGenericTypeDefinition(); Console.WriteLine($"List<int> 类型{closed}"); Console.WriteLine($"List<> 类型{unBound}"); Console.WriteLine($"List<> MakeGenericType执行后 类型{newClosed}"); Console.WriteLine($"List<int> GetGenericTypeDefinition执行后 类型{newUnBound}"); } }
参考: 《C#图解教程》、《果壳中的C#》