In the previous three articles, the basics of reflection and information objects were introduced. Reflection mainly applies to member objects such as constructors, properties, fields, methods, and events. The fourth article introduces the instantiation of types and event operations.
This article introduces type member operations and practical exercises.
Due to the extensive content, it is encouraged to practice hands-on.
[Image 1 Source: "C# 7.0 in a Nutshell: 19.2 Reflection and Calling Members"] So, how do you get the corresponding members using Type?
[Image 2 Source: "C# 7.0 in a Nutshell: 19.2 Reflection and Calling Members"] The methods above have versions for getting a single member or multiple members.
All *Info instances will be cached by the reflection API upon first use, which helps optimize the performance of the API.
1. MemberInfo
MemberInfo can retrieve information about member properties and provides access to the member metadata.
The MemberInfo class is the abstract base class used to obtain information about all members (constructors, events, fields, methods, and properties) of a class.
As seen in Image 1, MemberInfo is the base class for all reflection types and provides basic functionality for all members.
Using GetMember()
or GetMembers()
can retrieve one or more members of a type.
GetMembers()
returns all public members of the current type (and its base classes).
The GetMember
method can retrieve a specific member by name. Since members (methods, properties, etc.) may be overloaded, this method returns an array.
For example
MemberInfo[] members = type.GetMember(test);
1.1 Exercise - Get Type Members and Output Information
Create a type
public class MyClass
{
private static string A { get; set; }
public string B;
public string C { get; set; }
[Required]
public int Id { get; set; }
[Phone]
public string Phone { get; set; }
[EmailAddress]
public string Email { get; set; }
static MyClass()
{
A = 666;
}
public MyClass()
{
B = 666;
}
public MyClass(string message)
{
C = message;
}
public string Add(string a, string b)
{
return a + b;
}
}</code></pre>
Print
Type type = typeof(MyClass);
MemberInfo[] members = type.GetMembers();
foreach (var item in members)
{
Console.WriteLine(item.Name + | + item.MemberType);
}
Output
get_C | Method
set_C | Method
get_Id | Method
set_Id | Method
get_Phone | Method
set_Phone | Method
get_Email | Method
set_Email | Method
Add | Method
GetType | Method
ToString | Method
Equals | Method
GetHashCode | Method
.ctor | Constructor
.ctor | Constructor
C | Property
Id | Property
Phone | Property
Email | Property
B | Field
1.2 MemberType Enumeration
There is a property named MemberType
in MemberInfo
that is an enumeration of MemberType.
The definition of the MemberType
enumeration is as follows
Name
Value
Description
All
191
Specifies all member types
Constructor
1
Specifies that the member is a constructor
Custom
64
Specifies that the member is a custom member type
Event
2
Specifies that the member is an event
Field
4
Specifies that the member is a field
Method
8
Specifies that the member is a method
NestedType
128
Specifies that the member is a nested type
Property
16
Specifies that the member is a property
TypeInfo
32
Specifies that the member is a type
Where MemberType.All
is defined as All = NestedType | TypeInfo | Property | Method | Field | Event | Constructor
.
1.3 MemberInfo Get Member Method and Call
The following example retrieves method members through GetMembers
and invokes them with parameters.
This is just a demonstration. The instantiation and invocation of methods will be discussed in Section 3 of this article.
MemberInfo[] members = type.GetMembers();
foreach (var item in members)
{
// If the member is a method
if (item.MemberType == MemberTypes.Method)
{
// Output the parameter list of this method: parameter type + parameter name
foreach (ParameterInfo pi in ((MethodInfo)item).GetParameters())
{
Console.WriteLine(Parameter: Type={0}, Name={1}, pi.ParameterType, pi.Name);
}
// If the method has two parameters, invoke it
if (((MethodInfo)item).GetParameters().Length == 2)
{
// Invoke a method and pass parameters
MethodInfo method = (MethodInfo)item;
Console.WriteLine(Invoking a method, output result:);
Console.WriteLine(method.Invoke(example, new object[] { 1, 2 }));
}
}
}
1.4 Get Inherited Method Information (DeclaringType and ReflectedType)
In MemberInfo, there are three properties to obtain type information:
- MemberType indicates the function type of the member (e.g., field, property, method, etc.);
- DeclaringType returns the defining type of the member;
- ReflectedType returns the specific type from which
GetMembers
was called;
Since a method can be inherited or overridden, it is often necessary to understand related information to determine and call methods.
DeclaringType: If a type uses methods from its superclass or itself, it returns the source of that method;
ReflectedType: It returns the type from which members are obtained; that is, when a member instance is obtained from a Type, it returns the name of that Type;
Create two types
///
/// Base class
///
public class MyClassFather
{
///
/// Override ToString()
///
///
public override string ToString()
{
return base.ToString();
}
}
/// <summary>
/// Subclass
/// </summary>
public class MyClassSon : MyClassFather
{
}</code></pre>
In the console Program.Main, write
Type typeFather = typeof(MyClassFather);
Type typeSon = typeof(MyClassSon);
Type typeObj = typeof(object);
Type typeProgram = typeof(Program);
// To save steps, we won't use MemberInfo
MethodInfo methodObj = typeObj.GetMethod(ToString);
MethodInfo methodFather = typeFather.GetMethod(ToString);
MethodInfo methodSon = typeSon.GetMethod(ToString);
MethodInfo methodProgram = typeProgram.GetMethod(ToString);
Print DeclaringType
Console.WriteLine(methodObj.DeclaringType);
Console.WriteLine(methodFather.DeclaringType);
Console.WriteLine(methodSon.DeclaringType);
Console.WriteLine(methodProgram.DeclaringType);
Output
System.Object
Mytest.MyClassFather
Mytest.MyClassFather
System.Object
Analysis:
MyClassFather overrides the ToString
method, so the DeclaringType
obtained is MyClassFather;
MyClassSon inherits MyClassFather and directly uses the parent class's ToString()
method, so it returns MyClassFather;
The Program does not override ToString()
, so it returns Object;
2. Reflection from IL
The author's knowledge of IL is very limited, so only some simple content will be listed.
In the earlier exercise, we found
public string C { get; set; }
outputs
get_C | Method
set_C | Method
C | Property
The generated IL is as follows
.property instance string C()
{
.get instance string Mytest.MyClass::get_C()
.set instance void Mytest.MyClass::set_C(string)
}
Summary of IL generated for properties, indexers, and events:

For the three types above, when generating IL, corresponding methods are created, and can be accessed using GetMethods()
or GetMembers()
.
2.1 Get Properties Construct
Define a type
public class MyClass
{
private string Test;
public string A
{
get { return Test; }
}
public string B
{
set { Test = value; }
}
public string C { get; set; }
}</code></pre>
From previous examples, many are about retrieving the list of properties, but it was not possible to identify their constructions from them, for instance, in the MyClass type.
PropertyInfo
has a method GetAccessors()
which can obtain the corresponding information.
Method
Description
GetAccessors()
Returns an array containing the public get
and set
accessors reflected by the property currently being reflected.
GetAccessors(Boolean)
Returns an array containing both public and non-public (if specified) get
and set
accessors reflected by the property currently being reflected.
。
Usage Example
Type type = typeof(MyClass);
PropertyInfo[] list = type.GetProperties();
foreach (var item in list)
{
var c = item.GetAccessors();
foreach (var node in c)
{
Console.WriteLine(node);
}
Console.WriteLine(************);
}</code></pre>
Output
System.String get_A()
************
Void set_B(System.String)
************
System.String get_C()
Void set_C(System.String)
************
If we change the property C to
public string C { get; private set; }
then only the following will be output
System.String get_A()
************
Void set_B(System.String)
************
System.String get_C()
************
If you want to get private constructors, you can use .GetAccessors(true)
.
2.2 Property Methods
From reflection and IL, we know that a property automatically generates two methods.
We can obtain these methods through PropertyInfo.
Method
Description
GetSetMethod
Gets the set method, returns MethodInfo
GetGetMethod
Gets the get method, returns MethodInfo
GetAccessors
Obtains a collection of the above two methods, returns MethodInfo[]
Creating a Property
public string C { get; set; }
Type type = typeof(MyClass);
PropertyInfo property = type.GetProperty(C);
// Specify whether to get get or set
MethodInfo set = property.GetSetMethod();
MethodInfo get = property.GetGetMethod();
MethodInfo[] all = property.GetAccessors();</code></pre>
3. Method Operations
We must remember that reflection is the use of metadata; only instances can be executed and called.
Here, let's talk about the nameof
keyword. The nameof has no effect; it will not impact the program in any way.
nameof(T) can output T, for example, nameof(Program)
outputs Program
.
So when is it useful?
When writing code, we use IDEs like Visual Studio, and using nameof with strongly typed types allows for finding references, jumping to definitions, retrieving comments, etc. If refactoring is needed, all references can be quickly renamed.
If we use strings directly, it's easy to misspell names, and once a name is modified, we need to manually find and change all instances where that string appears.
To call an instance method, the following steps are involved:
Step
Type
Description
Get Type
Type
Obtain Type via assembly or other means
Get Instance
object
Create an instance using Activator.CreateInstance(type);
Get Method
MethodInfo or MemberInfo
Retrieve the corresponding method via Type
Set Parameter List
object[] parameters
Parameters passed during method call
Execute Method
.Invoke() method
Executing MethodInfo.Invoke()
Get Return Result
object
Return result obtained after executing the method
3.1 Various Ways to Invoke Methods
Firstly, let's define a type
public class MyClass
{
///
/// No parameters, returns void
///
public void A()
{
Console.WriteLine(A被执行);
}
/// <summary>
/// Has parameters, has return value
/// </summary>
/// <param name="a"></param>
/// <returns></returns>
public string B(string left)
{
Console.WriteLine(执行 B(string left));
return left + 666;
}
public string C(string left,int right)
{
Console.WriteLine(执行 C(string left,int right));
return left + right;
}
public string C(string left, string right)
{
Console.WriteLine(执行 C(string left, string right));
return left + right;
}
}</code></pre>
In Program, write code to obtain the Type and create an instance.
Type type = typeof(MyClass);
object example = Activator.CreateInstance(type);</code></pre>
3.1.1 Calling a Method
Let's call the method A()
// Get A
MethodInfo methodA = type.GetMethod(nameof(MyClass.A));
// Pass instance and execute instance's A method
methodA.Invoke(example, new Object[] { });</code></pre>
The method B
has one parameter, so we add a parameter when invoking it
object result;
// Get B
MethodInfo methodB = type.GetMethod(nameof(MyClass.B));
// Pass parameter
// Execute and get return result
result = methodB.Invoke(example, new[] {测试});</code></pre>
3.1.2 Getting Parameter List
In section 1.1, there are examples of code for obtaining method parameters. We won't elaborate on that here.
3.1.3 Getting Overloaded Methods
In the fourth part of the series "C# Reflection and Attributes," we introduced calling and overloading for constructors ConstructorInfo, and MethodInfo is quite similar.
Above, we retrieved MethodInfo using type.GetMethod(MethodName)
. For MyClass.C
, which has two overloads, we can specify which overload to use as follows.
// Get C
// Execute and get return result
MethodInfo methodC = type.GetMethod(nameof(MyClass.C), new Type[] {typeof(string), typeof(string)});
result = methodC.Invoke(example, new string[] {测试, 测试});
// result = methodC.Invoke(example, new Object[] {测试, 测试});
Thus, we have discussed the instantiation and operation of types, constructors, delegates, and methods.
Next, we will discuss how to set and retrieve values for properties and fields.
文章评论