1. 程式人生 > 其它 >C# 反射(Reflection)

C# 反射(Reflection)

技術標籤:c#反射

首先說一下反射的優點:動態!!!
程式會被編譯器編譯成dll/exe,一般我們釋出的都是這個東西,然後在執行的時候會被CLR/JIT編譯成機器碼。

為什麼不直接通過編譯器編譯成機器碼呢?答案就是:通過CLR/JIT可以根據不同的平臺編譯成不同的機器碼,用以一次編譯多平臺執行。

微軟提供的反射工具主要是 System.Reflection

 Assembly assembly1 = Assembly.LoadFile(@"D:\RefTest.dll");//完整路徑
 Assembly assembly2 = Assembly.Load(@"RefTest"
);//程式集名稱,不帶字尾 //既可以是完整路徑也可以是程式集完整名稱 Assembly assembly3 = Assembly.LoadFrom(@"D:\RefTest.dll"); Assembly assembly = Assembly.LoadFrom(@"RefTest.dll");

反射的具體用法

新建一個專案:AnimalRefTest 新建介面IAnimal

using System;

namespace IRefTest
{
    public interface IAnimal
    {
        string CallName
(); } }

新建專案:DogRefTest 新建類 Dog

using IRefTest;
using System;

namespace DogRefTest
{
    public class Dog: IAnimal
    {
        public Dog()
        {
            this.name = "無名小狗";
        }

        public string name { set; get; }
        public int Age { set; get; }

        public
string food; private int foot; public string CallName() { Console.WriteLine($"狗叫:{this.name}"); return this.name; } } }

新建專案:CatRefTest 新建類 Cat

using IRefTest;
using System;

namespace CatRefTest
{
    public sealed class Cat : IAnimal
    {
        public Cat()
        {
            this.name = "無名小貓";
        }
        public Cat(string name)
        {
            this.name = name ?? throw new ArgumentNullException(nameof(name));
        }

        public string name { set; get; }
        /// <summary>
        /// 公開無參方法
        /// </summary>
        /// <returns></returns>
        public string CallName()
        {
            Console.WriteLine($"貓叫:{this.name}");
            return this.name;
        }
        /// <summary>
        /// 公開單引數方法
        /// </summary>
        /// <param name="what"></param>
        public void CallWhatPublic(string what)
        {
            Console.WriteLine($"公開單引數方法:{what}");
        }
        /// <summary>
        /// 私有單引數方法
        /// </summary>
        /// <param name="what"></param>
        private void CallWhatPrivate(string what)
        {
            Console.WriteLine($"私有單引數方法:{what}");
        }

    }
}

新建一個專案RefTest,新建配置檔案,新增內容

<add key="IAnimalConfig" value="CatRefTest,CatRefTest.Cat"/>

新建類AnimalFactory

using IRefTest;
using System;
using System.Configuration;
using System.Reflection;

namespace Build.Reflection
{
    public class AnimalFactory
    {
        private static string IAniamlConfig = ConfigurationManager.AppSettings["IAnimalConfig"];
        private static string DLLName = IAniamlConfig.Split(',')[0];
        private static string TypeName = IAniamlConfig.Split(',')[1];

        public static IAnimal GetAnimal() {
            Assembly assembly = Assembly.LoadFrom(DLLName);
            Type type = assembly.GetType(TypeName);//完全限定名
            var obj = Activator.CreateInstance(type);
            IAnimal animal = (IAnimal)obj;
            return animal;
        }
    }
}

main方法中輸入程式碼並執行

using Build.Reflection;

namespace Build
{
    class Program
    {
        static void Main(string[] args)
        {
            var animal = AnimalFactory.GetAnimal();
            animal.CallName();//輸出:
        }
    }
}

輸出
在這裡插入圖片描述

感覺和IOC有點像啊,應該是用了類似的方法實現的。

這樣的話,就意味著,如果我們軟體設計之初只支援Cat類,但是後來需求變更,需要支援Dog,那麼我們只需要修改配置檔案就可以在不修改原始碼的情況下,只需要在根目錄新增DogRefTest.dll,並更新配置檔案即可支援,實現熱更新。

最後總結一下反射的缺點:

  • 寫起來複雜
  • 逃脫了編譯器的檢查,出錯概率高
  • 效能問題,與直接呼叫之間效能差距可能百倍之多,但是大部分情況下不會影響程式的效能

反射的實際應用:MVC的路由,EF
這些應用可以空間換時間,第一次載入完直接存入快取即可大大提高效能。