在C#中,是否可以使用反射来获取基于而不是的字符串的对象实例?
例如:
Activator.CreateInstance(Type.GetType(objName));
使用反射。
是否可以使用不使用反射的“字符串到对象”实现替换工厂类的经典if \ else结构?
我听说有,但我不知道如果没有反思你会怎么做。
答案 0 :(得分:4)
但它不是一个简单的解决方案。基本上,您创建一个动态方法,然后从中创建一个委托并使用它。
public static BaseBuilder Create(Type builderType, HttpContextBase httpContext, PathDataDictionary pathData)
{
if (!builderType.IsSubclassOf(baseBuilderType)) return null;
BuilderConstructorDelegate del;
if (builderConstructors.TryGetValue(builderType.FullName, out del))
return del(httpContext, pathData);
DynamicMethod dynamicMethod = new DynamicMethod("CreateBaseBuilderInstance", builderType, constructorMethodArgs, builderType);
ILGenerator ilGenerator = dynamicMethod.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldarg_1);
ilGenerator.Emit(OpCodes.Newobj, builderType.GetConstructor(constructorMethodArgs));
ilGenerator.Emit(OpCodes.Ret);
del = (BuilderConstructorDelegate)dynamicMethod.CreateDelegate(typeof(BuilderConstructorDelegate));
builderConstructors.TryAdd(builderType.FullName, del);
return del(httpContext, pathData);
}
以下是我在Builder for ASP.NET
中使用的一些代码BuilderFactory中的框架。
如果代码中不清楚,您应该知道,一旦您拥有委托,那么该删除将存储在上面代码中名为builderConstructors的字典中。所以下次工厂只使用代表。
在这种特殊情况下,类在其构造函数中需要两个参数。如果你正在为你的类使用默认构造函数,那么事情会更简单。
答案 1 :(得分:3)
由于您在问题中使用了依赖注入标记,因此依赖注入框架通常会为您执行此操作。总是存在反射,但是大多数都会有一个缓存机制,可以在下次请求对象时阻止任何反射。特别是当您的类型是具有默认构造函数的具体类型时(如您在问题中所示),不需要注册。例如,使用Simple Service Locator时,请求将如下所示:
object instance = ServiceLocator.Current.GetInstance(Type.GetType(objName));
当您不想使用依赖注入框架时,您可以做的是为创建这些对象生成委托,并将它们缓存在以objName
为关键字的字典中(这基本上是什么DI框架会做)。虽然您可以使用LCG(如Shiv所示),但使用新的.NET 3.5 Expression树可以轻松实现:
private static Dictionary<string, Func<object>> delegates =
new Dictionary<string, Func<object>>();
public static object CreateObjectByName(string name)
{
if (delegates.ContainsKey(name))
{
return delegates[name]();
}
else
{
Func<object> creator = CreateDelegateFor(Type.GetType(name));
// TODO: Don't forget to make this thread-safe :-)
delegates[name] = creator;
}
}
// .NET Expression tree magic!
private static Func<object> CreateDelegateFor(Type type)
{
var constructor = type.GetConstructors().First();
var newServiceTypeMethod = Expression.Lambda<Func<object>>(
Expression.New(constructor, new Expression[0]),
new ParameterExpression[0]);
return newServiceTypeMethod.Compile();
}
答案 2 :(得分:1)
您可以使用Microsoft.VisualBasic.Interaction.CreateObject
,但这仅适用于COM对象。 (从好的方面来说,这允许您在其他人的计算机上创建对象。)