C# 反射(Reflection)
程序员文章站
2024-01-20 22:32:16
...
首先说一下反射的优点:动态!!!
程序会被编译器编译成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
这些应用可以空间换时间,第一次加载完直接存入缓存即可大大提高性能。