不使用Reflection的C#String to Object

时间:2010-11-12 03:03:45

标签: c# reflection dependency-injection

在C#中,是否可以使用反射来获取基于而不是的字符串的对象实例?

例如:

Activator.CreateInstance(Type.GetType(objName));

使用反射。

是否可以使用不使用反射的“字符串到对象”实现替换工厂类的经典if \ else结构?

我听说有,但我不知道如果没有反思你会怎么做。

3 个答案:

答案 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的字典中。所以下次工厂只使用代表。

在这种特殊情况下,类在其构造函数中需要两个参数。如果你正在为你的类使用默认构造函数,那么事情会更简单。

High Performance Class Factory

答案 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对象。 (从好的方面来说,这允许您在其他人的计算机上创建对象。)