简体   繁体   中英

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?

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?

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

framework in the 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. 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). While you can use LCG (as Shiv showed), it has gotten much easier with the new .NET 3.5 Expression trees:

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. (On the plus side, this allows you to create objects on other people's computers.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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