SoFunction
Updated on 2025-03-07

Tutorial on the Usage of Reflection in dotNet

This article describes the usage of reflection in dotNet. Share it for your reference, as follows:

Refer to MSDN:

ms-help://.2003/.2003FEB.2052/cpguide/html/

outline:

1. What is reflection
2. The relationship between namespace and assembly
3. What is the use of obtaining type information during the runtime?
4. How to use reflection to obtain types
5. How to dynamically create objects based on types
6. How to obtain methods and dynamically call methods
7. Dynamically create a delegation

1. What is reflection

Reflection, Chinese translation as reflection

This is the way to obtain runtime type information in .Net. The application of .Net consists of several parts: "Assembly", "Module", and "Class". Reflection provides a programming method that allows programmers to obtain relevant information of these components during the program run, such as:

The Assembly class can obtain the information of running assembly, dynamically load the assembly, find type information in the assembly, and create instances of that type.

The Type class can obtain the type information of the object, which contains all the elements of the object: methods, constructors, properties, etc. The information of these elements can be obtained through the Type class and called it.

MethodInfo contains the information of the method. Through this class, you can get the name, parameters, return value, etc. of the method, and it can be called.

And so on, there are FieldInfo, EventInfo, etc., these classes are all included in the namespace.

2. The relationship between namespace and assembly

Many people may still be very unclear about this concept. For qualified .Net programmers, it is necessary to clarify this point.

Namespaces are similar to Java packages, but are not exactly the same, because Java packages must be placed according to the directory structure, and namespaces are not required.

Assembly is the smallest unit of execution of .Net applications, and compiled .dll and .exe are all assembly parts.

The relationship between assembly and namespace does not correspond one by one, nor does it contain each other. There can be multiple namespaces in an assembly, and a namespace can also exist in multiple assembly components. This may be a bit vague. For example:

Assembly A:

namespace N1
{
  public class AC1 {…}
  public class AC2 {…}
}
namespace N2
{
  public class AC3 {…}
  public class AC4{…}
}

Assembly B:

namespace N1
{
  public class BC1 {…}
  public class BC2 {…}
}
namespace N2
{
  public class BC3 {…}
  public class BC4{…}
}

These two assembly parts have two namespaces N1 and N2, and each declares two classes, which is completely OK. Then we refer to assembly A in an application. In this application, we can see that the classes below N1 are AC1 and AC2, and the classes below N2 are AC3 and AC4.

Then we remove the reference to A and add the reference to B. Then the classes under N1 that we can see in this application become BC1 and BC2, and the same is true for N2.

If we reference these two assembly parts at the same time, we can see four categories below N1: AC1, AC2, BC1 and BC2.

At this point, we can understand a concept. The namespace only means that a type belongs to which ethnic group, such as some are Han and some are Hui people; and the assembly shows where a type lives, such as someone lives in Beijing and some are Shanghai; then there are Han and Hui people in Beijing, and there are Han and Hui people in Shanghai, which is not contradictory.

As we said above, an assembly is a place where a type lives. If you want to use a class in a program, you must tell the compiler where the class lives so that the compiler can find it, that is, the assembly must be referenced.

So if you are not sure where this class is when writing a program, and you just know its name, you can't use it? The answer is yes, this is reflection, which is to provide the address of this type when the program is running and find it.
If you are interested, continue reading.

3. What is the use of obtaining type information during the runtime?

Some people may wonder, since you can write good code during development, why do you still do it in the runtime? It is not only cumbersome, but also the efficiency is also affected.

This is a matter of opinion. It is just like early binding and late binding, and it is applied to different occasions. Some people oppose late binding, because of loss of efficiency, but many people have not realized that they have used late binding when they enjoy the benefits of virtual functions. This question is not something that can be explained clearly in just a few words, so I just clicked.

My opinion is that late binding can bring a lot of design convenience, and appropriate use can greatly improve the reusability and flexibility of the program, but everything has two sides, and when used, it needs to be measured repeatedly.

Then, what is the use of obtaining type information during the runtime?

Let me give you an example to illustrate that many software developers like to leave some interfaces in their software. Others can write some plug-ins to expand the functions of the software. For example, I have a media player, and I hope that it can easily expand the recognized format in the future. Then I declare an interface:

public interface IMediaFormat
{
string Extension {get;}
Decoder GetDecoder();
}

This interface contains an Extension property, which returns the supported extension, and another method returns a decoder object (here I assume a Decoder class, which provides the function of decoding file streams, which can be derived from, and the extension plug-in can be derived). Through the decoder object, I can interpret the file stream.

Then I stipulate that all decoding plugins must derive a decoder and implement this interface, return the decoder object in the GetDecoder method, and configure its type name into my configuration file.

In this way, I don’t need to know the type of formats to be expanded in the future when developing the player. I just need to get the type names of all decoders from the configuration file, and dynamically create media format objects and convert them to the IMediaFormat interface for use.
 
This is a typical application of reflection.

4. How to use reflection to obtain types

First, let’s look at how to obtain type information.

There are two ways to obtain type information, one is to obtain instance objects

At this time, I just got this instance object. The way I got may be a reference to an object or an interface, but I don't know its exact type. I need to understand, so I can get the type object of the instance object by calling the declared method GetType. For example, within a certain method, I need to determine whether the passed parameters implement a certain interface. If it is implemented, a method of the interface is called:

…
public void Process( object processObj )
{
 Type t = ();
 if( ("ITest") !=null )
     …
}
…

Another way to obtain types is through and methods, such as:

Copy the codeThe code is as follows:
Type t = ("");

It should be noted that we talked about the relationship between namespace and assembly. To find a class, you must specify the assembly it is located in, or call GetType on the already obtained Assembly instance.

In this assembly, the type can only be written with the type name. Another exception is that the type declared in this assembly can also omit the assembly name (the .Net assembly is referenced by default when compiling, unless it is explicitly specified not to reference it during compilation). For example:

It is declared in, the above Type t = ("") is correct

It is declared in, then:
("") can only get empty references.

must:

Copy the codeThe code is as follows:
Type t = (",,Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");

5. How to dynamically create objects based on types

Provides methods to create objects dynamically based on types, such as creating a DataTable:

Type t = (",,Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
DataTable table = (DataTable)(t);

Example 2: Create an object based on a constructor with parameters

namespace TestSpace {
public class TestClass
{
  private string _value;
  public TestClass(string value) {
 _value=value;
  }
}
}
…
Type t = ("");
Object[] constructParms = new object[] {"hello"}; //Constructor parametersTestClass obj = (TestClass)(t,constructParms);
…

Put the parameters into an Object array in order

6. How to obtain methods and dynamically call methods

namespace TestSpace
{
  public class TestClass {
   private string _value;
   public TestClass() {
   }
   public TestClass(string value) {
    _value = value;
   }
   public string GetValue( string prefix ) {
    if( _value==null )
      return "NULL";
    else
      return prefix+" : "+_value;
   }
   public string Value {
   set {
     _value=value;
    }
    get {
     if( _value==null )
     return "NULL";
     else
     return _value;
    }
   }
  }
}

The above is a simple class that contains a constructor with parameters, a GetValue method, and a Value property. We can get the method through the name of the method and call it, such as:

//Get type informationType t = ("");
//Constructor parametersobject[] constuctParms = new object[]{"timmy"};
//Create an object according to the typeobject dObj = (t,constuctParms);
//Get method informationMethodInfo method = ("GetValue");
//Call some flag bits of the method, the meaning here is Public and is an instance method, which is also the default valueBindingFlags flag =  | ;
//GetValue method parametersobject[] parameters = new object[]{"Hello"};
//Calling the method, using an object to receive the return valueobject returnValue = (dObj,flag,,parameters,null);

The calls of properties and methods are similar, you can also refer to MSDN

7. Dynamically create a delegation

Delegates are the basis for implementing events in C#. Sometimes, delegates are inevitably created dynamically. In fact, delegates are also a type: all delegates are derived from this class.

Provides some static methods to dynamically create a delegate, such as a delegate:

namespace TestSpace {
  delegate string TestDelegate(string value);
  public class TestClass {
  public TestClass() {
     }
     public void GetValue(string value) {
       return value;
     }
  }
}

Example of usage:

TestClass obj = new TestClass();
//Get type, in fact, you can also use typeof to get the type directly hereType t = ("");
//Create a proxy, pass in type, object to create a proxy, and method nameTestDelegate method = (TestDelegate)(t,obj,"GetValue");
String returnValue = method("hello");

For more information about C# related content, please check out the topic of this site:C# data structure and algorithm tutorial》、《Summary of WinForm control usage"and"Introduction to C# object-oriented programming tutorial

I hope this article will be helpful to everyone's C# programming.