Learn about type information at .NET runtime (2)

zhaozj2021-02-17  49

Design mode used by reflection classes

The most commonly used methods in the System.Reflection class use unified mode. Members of Module, Type, and MemberInfo classes use the design patterns shown in the table below.

Member signature

Description

MyInstance [] Findxxx (Filter, Filtercriteria)

Find and return to the filter type list, or return an empty array without implementing any type of matching filter.

For example: Type.FindInterfaces

Myinstance getxxx ()

Return from uniquely specified types. If there is no such type, the member will return NULL (Noth in Microsoft Visual Basic .NET). Note that uniquely specifies an instance.

For example: Type.GetInterface

Myinstance [] getxxxs ()

Returns all public types. If there is no public type, the member will return an empty array.

Type.Getfields

Myinstance [] getxxxs ()

Returns all types specified by . If there is no such type, the member will return an array. Please note that does not necessarily specify a unique instance.

Another commonly used design pattern is a delegate. They typically use the result set of the method of returning an object array in the reflection to screen.

Reflection safety precautions

If you provide access to non-public information, it will bring security risks. If the code is allowed to understand a type of non-public information, then the code may access the code, data, and other information you need to confidential. Therefore, .NET framework security enforces some rules to determine which degree of reflection can use to understand the type information and access types. DeflectionPermission or SecurityPermission, depending on the operation performed, may require sequentialization.

In the case of unauthorized case, all code can use reflection to perform the following tasks:

Get information about public types and its public members.

Understand the modules and assemblies where the code is located.

Enumerate public types.

Enumerates the non-public type with the use of reflected code in the same program.

Enumerate assembling and modules.

Call a public member.

Calling a member access member called code base class.

Calling a member of the assembly of the calling code assembly.

To understand information about non-public members, the caller must have ReflectionPermission, which indicates that type information can be obtained. If this permission does not have this permission, the code will not be able to use the GET method on Type, Assembly, and Module to get information about non-public members (even if it belongs to it.).

To use reflection to call the method that cannot be accessed by the general type of system accessibility rule or access to the code, you must give a member access to the ReflectionPermission.

Note It is recommended to give the security policy to refuse to grant the ReflectionPermission from the code source from the Internet.

Serialized SecurityPermission provides the ability to get and set any non-transient data fields (ie, not only in memory, not only if you can access these fields. This permissions make the code understand and change the private status of the instance. (In addition to granting the correct permissions, the type tagged as sequentialization in metadata.)

Link request check

If the method or delegate has a linkDemand for a P authority, the run library will perform a link request check for the method or the delegated caller to verify that P authority has been granted to the caller. This link request check is performed when you understand the type information and the call. The public API that uses the MethodInfo parameters should be avoided, especially for highly trusted code. Otherwise, the call permissions may be easily bypass malicious code. For example, it is envisaged in a highly trusted code to have a public API using a MethodInfo parameter. Assume that this public API is indirectly called MethodInfo.invoke to the provided parameters. If the public API does not perform the necessary permission check, due to the high trust of the security system, the call to the invoke method will always succeed. Even if the malicious code is free to call the method directly, it is still able to interconnect the method by calling the public API.

Dynamic loading and use type

Reflection provides an infrastructure used by a language compiler (such as Microsoft Visual Basic .NET and JScript) to implement implicit late binding. The binding is a process of finding a declaration (ie implementing) corresponding to the uniquely specified type. Since this process occurs during runtime instead of compile, it is called a late binding. Visual Basic .NET allows you to use implicit late bindings in your code; the Visual Basic compiler will call a helper method that uses reflection to get an object type. Parameters passing to the help method helps to call the correct way at runtime. These parameters include instances (objects) of their calling methods, name (string) of the modified method, and parameters pass to the called method (an array).

In the following code example, the Visual Basic compiler uses the reflex implicit to call the object called when compiling. The HelloWorld class has a PrintHello method that outputs "Hello World" in some text passed to the Printhello method. The Printhello method called in this example is actually type.invokemember; Visual Basic code allows the way to compile (early binding) during compile according to the type of object (Helloobj) instead of runtime (late binding) To call the Printhello method.

Custom binding

In addition to implicitly used by the compiler for advanced binding, reflecting can also explicitly use in the code to complete the late binding.

The public language runtime supports multiple programming languages, but the binding rules of these languages ​​are different. In the case of early binding, the code generator can fully control this binding. However, when the late binding is performed by reflection, the binding must be controlled with a custom binding. The Binder class provides custom control for members selection and calling.

With custom bindings, you can load an assembly at runtime to get information about the type of the program, and then call the method or to access the field or attribute of this type. This method can be used if you don't know the type of object when you compile (for example, when the object type depends on user input). The following code example displays the method of using reflex dynamic calls in the HelloWorld.dll program (first in Visual Basic .NET, then in C #).

[C #]

// this class is deployed as an assembly consisting of one DLL,

// Called HelloWorld.dll.

Using system;

Public class helloworld {

// constant hello world string.

Private const string m_helloWorld = "Hello World"; // default public constructor.

Public helloworld () {

}

// Print "Hello World" Plus the Passed Text.

Public void printhello (string txt) {

// output to the console.

Console.writeLine (M_HelloWorld " TX);

}

}

// illustrates reflection's late binding functionality.

// Calls the Printhello Method ON A Dynamically Loaded

// and created instance of the helloworld class.

Using system;

Using system.reflection;

Public class csharplatehello {

Public static void main () {

// load the assembly to us.

AskEMBLY ASSEM = askMBLY.LOAD ("HelloWorld");

// Get the Type to use from the assembly.

TYPE Hellote = askEM.GETTYPE ("HelloWorld");

// Get the method to call from the Type.

MethodInfo PrintMethod = Hellotype.getMethod ("Printhello");

// Create An Instance of The HelloWorld Class.

Object obj = activator.createInstance (Hellotype);

// CREATE The args array.

Object [] args = new object [1];

// set the arguments.

Args [0] = "from csharp late bound";

// Invoke the printhello method.

PrintMethod.invoke (OBJ, ARGS);

}

}

InvokeMember and CreateInstance

Use the Type.InvokeMember to modify the type of member. The CreateInstance method of each class (such as system.activator and system.reflection.assembly is a special form of InvokeMember, which can create a specific type of instance. Binder class is used in these methods to perform overload decisions and parameters.

The following code example displays parameters forced (type mandatory) and members to select three possible combinations. In the first case, no parameters for mandatory or membership selection is required. In the second case, only members will be required. In the third case, only parameters are required.

[C #]

Public Class CustomBinderdriver

{

Public static void main (String [] arguments

{

Type T = TypeOf (CustomBinderDriver);

CustomBinder Binder = New CustomBinder ();

Bindingflags flags = bindingflags.invokeMethod | bindingflags.instance | bindingflags.public | bindingflags.static;

// Case 1. Neither Argument Coercion Nor Member Selection Is Needed.

Args = new object [] {};

T. InvokeMember ("PrintBob", Flags, Binder, NULL, ARGS);

// Case 2. Only Member Selection is needed.

Args = new object [] {42};

T. Invokemember ("PrintValue", Flags, Binder, NULL, ARGS;

// Case 3. Only Argument COERCION IS NEEDED.

Args = New Object [] {"5.5"};

T. InvokeMember ("PrintNumber", Flags, Binder, NULL, ARGS;

}

Public static void printbob ()

{

Console.WriteLine ("PrintBob");

}

Public Static Void PrintValue (Long Value)

{

Console.writeline ("PrintValue ({0})", Value);

}

Public Static Void PrintValue (String Value)

{

Console.writeline ("PrintValue /" {0} / ")" ", value);

}

Public Static Void PrintNumber (Double Value)

{

Console.writeline ("PrintNumber ({0})", Value);

}

}

When multiple members have the same name, the overload decision will be required. Binder.BindTomethod and Binder.bindtofield methods are used to resolve the binding with individual members. Binder.BindTomethod provides property resolution through GET and SET property accessors.

BindTomethod returns the methodBase to be called, and returns NULL if such calls cannot be made. Although the MethodBase return value is usually one of the values ​​contained in the Match parameter, it doesn't have to be.

When there is a BYREF parameter, the caller may need to retrieve these parameters. Therefore, if BindTomethod has operating the parameter array, Binder allows the parameter array to map back to its initial form. To achieve this, the order of the adjustment of the parameters must not be changed to the argument. When passing the parameters by name, the coupler will rearrange the array array, which is the parameters seen by the caller.

The available membership includes members defined in the type and any group. If bindingflags.nonpublic will return to the member, you will have any accessibility members. If bindingFlags.nonpublic is not specified, the coupler must enforce accessibility rules. When you specify a PUBLIC or NONPUBLIC binding flag, you must also specify the instance or static binding flag, otherwise no member will return.

If only one member has a given name, it is not necessary to make a callback, and the binding is performed on this method. The first case of the code example illustrates this: Only one printbob method is available, so there is no need to make a callback. If there are multiple members available, all of these methods will be passed to bindtomethod, which will select the correct method and return it. In the second case of code example, there are two methods called PrintValue. The call to BindTomethod will select the correct method.

ChangeType Performs parameters (Type Force) to convert real parameters to the type of parametric of the selected method. Even if the type is exactly match, ChangeType will be called for each parameter.

In the third case of the code example, the type of the "5.5" of the type is "5.5" is passed to the Double type. To make the call success, you must convert the string value "5.5" to the Double value. ChangeType will perform this conversion.

ChangType only performs non-destructive or expand conversion, as shown in the following table.

Source type

Target type

Any type

Its base type

Any type

The interface it implemented

Charr

UINT16, UINT32, INT32, UINT64, INT64, SINGLE, DOUBLE

Byte

Char, uint16, int16, uint32, int32, uint64, int64, single, double

Sbyte

INT16, INT32, INT64, SINGLE, DOUBLE

UINT16

UINT32, INT32, UINT64, INT64, SINGLE, DOUBLE

INT16

INT32, INT64, SINGLE, DOUBLE

Uint32

UINT64, INT64, SINGLE, DOUBLE

Int32

INT64, SINGLE, DOUBLE

Uint64

SINGLE, DOUBLE

Int64

SINGLE, DOUBLE

Single

Double

Non-reference type

Reference type

The Type class has a GET method that uses the Binder type parameter to resolve reference to specific members. Type.getConstructor, Type.getMethod and Type.getProperty searches for specific members of the current type by providing a member's signature information. Binder.selectMethod and Binder.selectProperty are called to select a given signature information for the appropriate method.

Access the default member

Any type can have a default member, that is, a member that is called when not given a given member name. The following code example calls the default member of the class1, and assigns the value it returned to I.

The default member is tagged with System.Refault.defaultmemberattribute. The following code example shows how to retrieve the default member by retrieving the custom properties of the default member.

[C #]

TYPE T = TypeOf (Defaultmembute);

DEFAULTMEMBERATTRIBUTE DEFMEM = (Defaultmembute) attribute.getcustomattribute (asmbly.getassembly (T), T);

MemberInfo [] Meminfo = T.getMember (DefMem.membername);

Use type.getDefaultmembers that may be simple and generate exact same results. However, if multiple default members are defined on the type, GetDefaultmembers will trigger InvalidOperationException. The following code example shows the syntax of getDefaultmembers.

[C #]

MEMBERINFO [] MEMINFO = T.GETDEFAULTMEMBERS (); the default member can call the default member by calling Type.InvokeMember by String.empty (") as a member name. InvokeMember retrieves Defaultmembutetribute from the type and calls it.

Access the default parameter value

Some languages ​​(such as C Hosting Extensions and Microsoft Visual Basic .NET) support to assign the default value to the parameters. For example, the following code example is a legitimate Visual Basic .NET declaration that assumes the default value to two parameters.

You can use the parameter properties to assign the default parameter value.

The default value of the parameters can be declared by the default parameters that specify which parameters are derived or the default parameters of the tail. For example, all of the following code examples are valid calls to myMethod.

[C #]

Mymethod (10, 55.3, 12);

Mymethod (10, 1.3); // c == 1

Mymethod (11); // b == 1.2, c == 1

To use the default value of reflective retrieval parameters, get the parameterinfo object of this parameter and then use the parameterInfo.defaultValue property to retrieve the default value. If there is no default value, the property will return to value.dbnull.

The following code example displays the default value of MyMethod to the console.

[C #]

MethodInfo M = T. GetMethod ("MyMethod");

Parameterinfo [] ps = m.getParameters ();

For (int i = 0; i

Console.writeline ("default value == {0}", PS [i] .defaultValue);

}

To call a method containing parameters with default values, use Type.Missing as the parameter value of the InvokeMember method. Thus, the late binding service can use the default value for the specified parameter value. If type.missing is passed for parameters without default, ArgumentException will be triggered. There is a point to pay attention to it, not all compilers' binding mechanisms will comply with Type.Missing these rules. Some couplets may not support this feature or may handle Type.Missing in a different way. When using Type.Missing, the default value does not have to be the end of the parameter value.

The C # language does not support the default parameters.

The following Visual Basic .NET code example displays how to call a method with the default parameters.

[Visual Basic]

Option Strict Off

Imports system

Imports system.reflection

Public Class OptionAlarg

Public Sub Mymethod (A as Integer, Optional B as Double = 1.2, Optional C as integer = 1)

Console.writeline ("a =" & a & "b =" & b & "c =" & c)

End Sub

END CLASS

Module Module1

Sub main ()

Dim o as new optionararg

DIM T as Type

T = gettype (optionararg)

DIM param as object () = {10, 20, 30}

T.invokeMember ("MyMethod", _

Bindingflags.public OR_

Bindingflags.instance or _

Bindingflags.invokeMethod Or_

BindingFlags.OptionalParambinding, _

Nothing, _

O, _

New Object () {10, 55.3, 12})

T.invokeMember ("MyMethod", _

Bindingflags.public OR_

Bindingflags.instance or _

Bindingflags.invokeMethod Or_

BindingFlags.OptionalParambinding, _

Nothing, _

O, _

New Object () {10, 1.3, Type.Missing}

T.invokeMember ("MyMethod", _

Bindingflags.public OR_

Bindingflags.instance or _

Bindingflags.invokeMethod Or_

BindingFlags.OptionalParambinding, _

Nothing, _

O, _

New Object () {10, Type.Missing, Type.Missing})

End Sub

End module

When the above method is used, the default parameters of the tail will be considered even if the caller is not specified any value. This is the most common way to call the method with the default parameters.

If you use MethodBase.Ivoke to call the method, you need to explicitly specify which parameters are default, the specified method is to deliver an array of objects containing Type.Missing for all non-valued parameters.

转载请注明原文地址:https://www.9cbs.com/read-28562.html

New Post(0)