1

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.

3
  • Why do you want to know? Commented Nov 12, 2010 at 3:10
  • @Rex Purely curiosity. I have heard that there is a way without using reflection and it is bothering me as it is not obvious how (and therefore I'm not sure I beleive there is!) Commented Nov 12, 2010 at 3:18
  • David, if any answers provided is the answer please mark the relevant one as the answer Commented Nov 14, 2010 at 17:07

3 Answers 3

4

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

Sign up to request clarification or add additional context in comments.

7 Comments

This is also using reflection.
This is a worthwhile answer. While it uses classes under System.Reflection.Emit, this is a one time cost. The actual execution does not make reflection calls.
Activator.CreateInstance is not dissimilar, in that it also caches the ctor method call after it's been resolved the first time.
Granted, but it's quite a bit faster than Activator.Create instance since reflection is used only the first time, after that it uses a delegate call. Using a delegate is as fast as making a virtual method call. Let's face it, if you want to create an instance of a class without call "new". There has to be reflection in use at some point.
Typo: "delete" should be "delegate"
|
3

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

Comments

1

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.)

3 Comments

Well I was thinking more along the lines of classes that derive from an interface. It still amazes me how powerful CreateObject is!
You mean classes that implement an interface :)
Can you call this method from C#?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.