代码之家  ›  专栏  ›  技术社区  ›  Robben_Ford_Fan_boy

字符串到对象,不使用反射

  •  1
  • Robben_Ford_Fan_boy  · 技术社区  · 14 年前

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

    例如:

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

    使用反射。

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

    我听说有,但我不明白你不经过深思熟虑怎么做。

    3 回复  |  直到 14 年前
        1
  •  3
  •   Steven    14 年前

    由于您在问题中使用了依赖注入标记,依赖注入框架通常会为您这样做。总是会涉及到反射,但大多数都有一个缓存机制,可以在下次请求对象时阻止任何反射。特别是当您的类型是具有默认构造函数的具体类型(如您在问题中所示)时,不需要注册。例如,当使用 Simple Service Locator ,请求如下:

    object instance = ServiceLocator.Current.GetInstance(Type.GetType(objName));
    

    当您不想使用依赖注入框架时,您可以做的是生成用于创建这些对象的委托,并将它们缓存到 objName 作为关键(这基本上是DI框架将要做的)。尽管您可以使用LCG(如Shiv所示),但使用新的.NET 3.5表达式树已经变得容易得多:

    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
  •  4
  •   Shiv Kumar    14 年前

    有,但不是一个简单的解决办法。实际上,您可以创建一个动态方法,然后从中创建一个委托并使用它。

    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

        3
  •  1
  •   Jonathan Allen    14 年前

    你可以用 Microsoft.VisualBasic.Interaction.CreateObject ,但这仅适用于COM对象。(另一方面,这允许您在其他人的计算机上创建对象。)