C # reflection (a)

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#》 

Guess you like

Origin www.cnblogs.com/dcz2015/p/11058193.html