假设有一个库包含多个实现了同一接口的类,用户可以通过配置文件指定要使用的具体类名和方法名。通过反射,可以在运行时根据配置加载相应的类型,并调用指定的方法。
// 假设有个接口和其实现类
public interface ICalculator
{
int Calculate(int a, int b);
}
public class Adder : ICalculator
{
public int Calculate(int a, int b) => a + b;
}
// 配置中读取类名
string className = "Adder";
Type calculatorType = Type.GetType(className);
// 创建实例并调用方法
ICalculator calculator = (ICalculator)Activator.CreateInstance(calculatorType);
int result = calculator.Calculate(3, 5);
如您提到的应用场景,系统需要记录用户修改了哪个实体类的哪些字段。通过反射,可以遍历实体类的所有属性,在用户修改后记录下变化的属性名和新旧值。
public class User
{
public string Name { get; set; }
public int Age { get; set; }
// 其他属性...
}
// 用户更新了一个User实例
var user = new User { Name = "OldName", Age = 30 };
foreach (var property in properties)
{
// 获取旧值(假设这是更改前的值)
var oldValue = property.GetValue(user);
// 模拟用户更改属性值
if (property.Name == "Name")
{
user.Name = "NewName";
}
// 再次获取新值
var currentValue = property.GetValue(user);
// 如果旧值与当前值不相等,则记录变更
if (!object.Equals(oldValue, currentValue) && property.CanRead && property.CanWrite)
{
LogChange(property.Name, oldValue, currentValue);
}
}
反射还可以用来调用非公开的构造函数,比如破坏单例模式时可能会用到:
public sealed class Singleton
{
private static readonly Singleton instance = new Singleton();
private Singleton() { }
public static Singleton Instance => instance;
// 通过反射破坏单例模式
public static Singleton CreateAnotherInstance()
{
ConstructorInfo ctor = typeof(Singleton).GetConstructor(
BindingFlags.Instance | BindingFlags.NonPublic,
null, Type.EmptyTypes, null);
return (Singleton)ctor.Invoke(null);
}
}
反射结合泛型,可以实现在不知道具体类型参数的情况下动态创建泛型类型实例:
public class GenericClass<T>
{
public T Value { get; set; }
}
Type genericType = typeof(GenericClass<>).MakeGenericType(typeof(string));
dynamic instance = Activator.CreateInstance(genericType);
instance.Value = "Hello, World!";
C#反射除了上述提到的几个典型应用场景外,还有以下一些常见的用途:
object obj = new MyDerivedClass();
Type type = obj.GetType();
// 检查类型是否实现了某个接口
bool isDisposable = typeof(IDisposable).IsAssignableFrom(type);
// 动态转换
if (type == typeof(MyDerivedClass))
{
MyDerivedClass derivedObj = (MyDerivedClass)obj;
// 使用转换后的对象...
}
public class MyClass
{
private int myPrivateField;
public void SetPrivateValue(int value)
{
this.myPrivateField = value;
}
}
var instance = new MyClass();
FieldInfo field = typeof(MyClass).GetField("myPrivateField", BindingFlags.NonPublic | BindingFlags.Instance);
field.SetValue(instance, 42); // 设置私有字段值
int fieldValue = (int)field.GetValue(instance); // 获取私有字段值
Assembly assembly = Assembly.GetExecutingAssembly();
foreach (Type type in assembly.GetTypes())
{
Console.WriteLine($"Type: {type.FullName}");
foreach (Attribute attribute in Attribute.GetCustomAttributes(type))
{
Console.WriteLine($" Attribute: {attribute.GetType().Name}");
}
}
总之,C#反射是一个强大的工具,它允许程序在运行时获得关于类型和程序集的信息,并基于这些信息进行操作,极大地增强了应用程序的灵活性和适应性。但需要注意的是,过度使用反射可能会降低性能,应谨慎权衡其带来的便利性和潜在的成本。
python推荐学习汇总连接:
50个开发必备的Python经典脚本(1-10)
50个开发必备的Python经典脚本(41-50)
————————————————
?最后我们放松一下眼睛