前言:
- 反射提高了程序的靈活性和擴展性。
- 降低耦合性,提高自適應能力。
- 它允許程序創建和控制任何類的對象,無需提前硬編碼目標類。
一、項目結構
創建項目的語句如下:
> mkdir ReflectionFolder
> cd .\ReflectionFolder\
> dotnet new classlib -n ReflectionTest.Abstractions
> dotnet new classlib -n ReflectionTest
> dotnet new sln -n ReflectionFolder
> dotnet sln add .\ConsoleApp\ConsoleApp.csproj
> dotnet sln add .\ReflectionTest\ReflectionTest.csproj
> dotnet sln add .\ReflectionTest.Abstractions\ReflectionTest.Abstractions.csproj
> cd .\ReflectionTest\
> dotnet add reference ..\ReflectionTest.Abstractions\ReflectionTest.Abstractions.csproj
> cd ..
> cd .\ConsoleApp\
> dotnet add reference ..\ReflectionTest\ReflectionTest.csproj
然後將解決方案打開。
在 ReflectionTest.Abstractions
項目中創建 ITestClass.cs
和 ITestGenericClass.cs
兩個文件:
#region [ITestClass.cs]
namespace ReflectionTest.Abstractions
{
public interface ITestClass
{
void TestMethod();
void TestMethodParam(int param);
void TestFunction();
void TestFunction(int param1);
void TestFunction(int param1, string param2);
}
}
#endregion
#region [IReflectionTest.cs]
namespace ReflectionTest.Abstractions
{
public interface ITestGenericClass<T1, T2>
{
void TestFunction<T3>(T1 param1, T2 param2, T3 param3);
int Id { get; set; }
string Name { get; set; }
}
}
#endregion
在 ReflectionTest
項目中創建 TestClass.cs
和 TestGenericClass.cs
兩個文件:
#region [TestClass.cs]
namespace ReflectionTest
{
public class TestClass : ITestClass
{
public TestClass()
{
Console.WriteLine("ctor 無參數");
}
public TestClass(int param1)
{
Console.WriteLine($"ctor 一個參數 {{ param1:{param1} }}");
}
public TestClass(int param1, string param2)
{
Console.WriteLine($"ctor 兩個參數 {{ param1:{param1}, param2:{param2} }}");
}
public void TestMethod()
{
Console.WriteLine("method 無參方法");
}
public void TestMethodParam(int param)
{
Console.WriteLine($"method 一個參數 {{ param:{param} }}");
}
public static void TestStaticMethod(int param)
{
Console.WriteLine("method 靜態無參方法");
}
public void TestFunction()
{
Console.WriteLine("function 無參方法");
}
public void TestFunction(int param1)
{
Console.WriteLine($"function 一個參數 {{ param1:{param1} }}");
}
public void TestFunction(int param1, string param2)
{
Console.WriteLine($"ctor 兩個參數 {{ param1:{param1}, param2:{param2} }}");
}
private void TestPrivateMethod(int param1)
{
Console.WriteLine($"function 一個無參私有方法 {{ param1:{param1} }}");
}
}
}
#endregion
#region [TestGenericClass.cs]
namespace ReflectionTest
{
public class TestGenericClass<T1, T2> : ITestGenericClass<T1, T2>
{
private TestGenericClass()
{
Console.WriteLine("ctor 無參數");
}
public void TestFunction<T3>(T1 param1, T2 param2, T3 param3)
{
Console.WriteLine($"ctor 三個參數 {{ param1:{param1}, param2:{param2}, param3:{param3} }}");
}
public int Id { get; set; }
public string Name { get; set; }
public string Description;
}
}
#endregion
二、創建對象並調用方法
在控制檯應用程序中進行測試
- 獲取類型
Assembly reflectionTestAssembly = Assembly.Load("ReflectionTest");
Type testClassType = reflectionTestAssembly.GetType("ReflectionTest.TestClass");
- 創建對象 (構造函數重載)
var testClass1 = Activator.CreateInstance(testClassType) as ITestClass;
var testClass2 = Activator.CreateInstance(testClassType, new object[] { 123 }) as ITestClass;
var testClass3 = Activator.CreateInstance(testClassType, new object[] { 123, "Upgrader" }) as ITestClass;
- 調用方法 (無參非重載)
var testMethod = testClassType.GetMethod("TestMethod");
testMethod.Invoke(testClass1, null);
- 調用方法 (一個參數非重載)
var testMethodParam = testClassType.GetMethod("TestMethodParam");
testMethodParam.Invoke(testClass1, new object[] { 123 });
- 調用方法 (靜態方法)
var testStaticMethod = testClassType.GetMethod("TestStaticMethod");
testStaticMethod.Invoke(testClass1, new object[] { 123 });
testStaticMethod.Invoke(null, new object[] { 123 });
- 調用方法 (重載無參)
var testFunction1 = testClassType.GetMethod("TestFunction", new Type[] { });
testFunction1.Invoke(testClass1, null);
- 調用方法 (重載有參)
var testFunction2 = testClassType.GetMethod("TestFunction", new Type[] { typeof(int) });
testFunction2.Invoke(testClass1, new object[] { 123 });
- 調用方法 (重載有參)
var testFunction3 = testClassType.GetMethod("TestFunction", new Type[] { typeof(int), typeof(string) });
testFunction3.Invoke(testClass1, new object[] { 123, "Upgrader" });
- 調用私有方法
var testPrivateMethod = testClassType.GetMethod("TestPrivateMethod", BindingFlags.Instance | BindingFlags.NonPublic);
testPrivateMethod.Invoke(testClass1, new object[] { 123 });
- 獲取類型 (泛型)
var testGenericClassType = reflectionTestAssembly.GetType("ReflectionTest.TestGenericClass`2");
var makeGenericType = testGenericClassType.MakeGenericType(new Type[] { typeof(int), typeof(string) });
- 訪問私有構造函數創建對象
var testGenericClass = Activator.CreateInstance(makeGenericType, true);
- 調用泛型方法
var testFunction = makeGenericType.GetMethod("TestFunction");
var makeTestFunction = testFunction.MakeGenericMethod(new Type[] { typeof(DateTime) });
makeTestFunction.Invoke(testGenericClass, new object[] { 123, "Upgrader", DateTime.Now });
三、創建對象並修改屬性和字段
var testGenericClass2 = Activator.CreateInstance(makeGenericType, true) as TestGenericClass<int, string>;
Type type = testGenericClass2.GetType();
- 遍歷屬性
foreach (var prop in type.GetProperties())
{
if (prop.Name.Equals("Id"))
prop.SetValue(testGenericClass2, 321);
else if (prop.Name.Equals("Name"))
prop.SetValue(testGenericClass2, "Achovin");
Console.WriteLine($"{{ typeName:{type.Name}, Name:{prop.Name}, Value:{prop.GetValue(testGenericClass2)} }}");
}
- 便利字段
foreach (var field in type.GetFields())
{
if (field.Name.Equals("Description"))
field.SetValue(testGenericClass2, "Description");
Console.WriteLine($"{{ typeName:{type.Name}, Name:{field.Name}, Value:{field.GetValue(testGenericClass2)} }}");
}