简体   繁体   English

C#字符串到对象而不使用反射

[英]C# String to Object without using Reflection

In C#, is it possible to get an instance of an object based on a string without using Reflection? 在C#中, 使用反射就可以基于字符串获取对象的实例吗?

For example: 例如:

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

uses reflection. 使用反射。

Is it possible to replace the classic if\\else structure of a factory class with a "string to object" implementation that dosn't use reflection? 是否可以将工厂类的经典if \\ else结构替换为不使用反射的“字符串到对象”实现?

I have heard that there is, but I don't see how you would do it without reflection. 我听说那里有,但是我不明白你会怎么做而没有反思。

There is but it's not a simple solution. 有,但这不是一个简单的解决方案。 Essentially you create a dynamic method and then create a delegate from that and use it. 本质上,您创建一个动态方法,然后从中创建一个委托并使用它。

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);
}

Here is some code I use in the Builder for ASP.NET 这是我在用于ASP.NETBuilder中使用的一些代码

framework in the BuilderFactory. BuilderFactory中的框架。

If it's not clear in the code, you should know that once you have a delegate then that delete is stored in the dictionary called builderConstructors in the code above. 如果代码中不清楚,则应该知道,一旦有了委托,则该删除将存储在上述代码中名为builderConstructors的字典中。 So the next time the factory simply uses the delegate. 因此,下次工厂仅使用委托时。

In this particular case the class requires two parameters in its constructor. 在这种特殊情况下,该类在其构造函数中需要两个参数。 If you're using the default constructor for your classes things are a little simpler. 如果您对类使用默认的构造函数,则事情会更简单一些。

High Performance Class Factory 高性能班级工厂

Since you're using the dependency-injection tag in your question, Dependency Injection frameworks would typically do this for you. 由于您在问题中使用了依赖注入标签,因此依赖注入框架通常会为您完成此操作。 There is always reflection involved, but most of them would have a caching mechanism that prevents any reflection the next time an object is requested. 总是涉及反射,但是其中大多数将具有缓存机制,该机制可防止在下次请求对象时进行任何反射。 Especially when your type is a concrete type with a default constructor (as you shown in your question) no registration is required. 特别是当您的类型是具有默认构造函数的具体类型时(如您的问题所示),则不需要注册。 For instance, when using the Simple Service Locator , the request would look like this: 例如,当使用简单服务定位器时 ,请求将如下所示:

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

When you don't want to use a dependency injection framework, what you can do is generate delegates for the creation of those objects and cache them in a dictionary with objName as key (this is basically what DI frameworks will do). 当您不想使用依赖项注入框架时,您可以做的是生成用于创建这些对象的委托,并将它们缓存在以objName作为键的字典中(这基本上就是DI框架所要做的)。 While you can use LCG (as Shiv showed), it has gotten much easier with the new .NET 3.5 Expression trees: 虽然您可以使用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();
}

You can use Microsoft.VisualBasic.Interaction.CreateObject , but that only applies to COM objects. 您可以使用Microsoft.VisualBasic.Interaction.CreateObject ,但这仅适用于COM对象。 (On the plus side, this allows you to create objects on other people's computers.) (从好的方面来说,这使您可以在其他人的计算机上创建对象。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM