C# 反射(Reflection)
阿新 • • 發佈:2020-12-21
首先說一下反射的優點:動態!!!
程式會被編譯器編譯成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
這些應用可以空間換時間,第一次載入完直接存入快取即可大大提高效能。