C# 中的常用的反射方法

前言:

  1. 反射提高了程序的靈活性和擴展性。
  2. 降低耦合性,提高自適應能力。
  3. 它允許程序創建和控制任何類的對象,無需提前硬編碼目標類。

一、項目結構

創建項目的語句如下:

> 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.csITestGenericClass.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.csTestGenericClass.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)} }}");
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章