面试题答案
一键面试1. 程序集的加载
在 C# 中,可以使用 Assembly.Load
系列方法来加载外部程序集。例如,若程序集在本地文件系统,可以使用 Assembly.LoadFrom
方法:
string assemblyPath = "path/to/your/assembly.dll";
Assembly assembly = Assembly.LoadFrom(assemblyPath);
如果是从字节数组加载(比如从网络下载后),可以使用 Assembly.Load
方法:
byte[] assemblyBytes = GetAssemblyBytes();// 假设此方法获取字节数组
Assembly assembly = Assembly.Load(assemblyBytes);
2. 类型的查找与实例化
加载程序集后,可通过 Assembly.GetType
方法查找特定类型。找到类型后,使用 Activator.CreateInstance
方法实例化对象:
string typeName = "YourNamespace.YourTypeName";
Type targetType = assembly.GetType(typeName);
if (targetType != null)
{
object instance = Activator.CreateInstance(targetType);
}
如果类型有参数化构造函数,可以使用 Activator.CreateInstance(Type, Object[])
方法,传入构造函数参数数组:
object[] constructorArgs = { "arg1", 42 };
object instance = Activator.CreateInstance(targetType, constructorArgs);
3. 方法的调用
实例化对象后,可通过反射调用其方法。先获取 MethodInfo
,然后使用 MethodInfo.Invoke
方法:
MethodInfo methodInfo = targetType.GetMethod("YourMethodName");
if (methodInfo != null)
{
object[] methodArgs = { "methodArg1" };
object result = methodInfo.Invoke(instance, methodArgs);
}
4. 反射带来的性能问题
- 性能开销大:反射操作需要在运行时解析类型、方法等元数据,相比直接调用方法,会有显著的性能损失。
- JIT 优化受限:JIT(Just - In - Time)编译器无法像对常规代码那样对反射代码进行深度优化,因为反射的类型和方法调用在编译时是未知的。
5. 优化策略
- 缓存反射结果:缓存
Assembly
、Type
、MethodInfo
等反射对象,避免重复查找和加载。例如,使用Dictionary
来存储已经获取的Type
或MethodInfo
:
private static readonly Dictionary<string, Type> typeCache = new Dictionary<string, Type>();
private Type GetCachedType(string typeName, Assembly assembly)
{
if (typeCache.TryGetValue(typeName, out Type type))
{
return type;
}
type = assembly.GetType(typeName);
if (type != null)
{
typeCache.Add(typeName, type);
}
return type;
}
- 使用动态方法:对于频繁调用的反射方法,可以使用
System.Reflection.Emit
动态生成代码,以获得接近直接调用的性能。例如,DynamicMethod
类允许在运行时生成方法并执行。 - 尽量减少反射操作:在性能敏感的代码段,避免使用反射。如果可能,将反射操作限制在初始化阶段,后续操作使用常规的对象调用。