다음을 통해 공유


Activator.CreateInstance - System.Type vs. Generic Method

Daniel Moth asked, in his post, how to choose between a generic type parameter vs. a formal parameter of typed as System.Type. For example, the following two members seem equivalent.

public class Activator {
public static object CreateInstance(Type instanceType);
// or?
public static T CreateInstance<T>();
}

The generic method seems slightly better, as it returns a strongly typed return value. Should you always just use generics in such cases and never have methods that take System.Type?

The answer is no and the reason is that to call a generic method, you have to know the type arguments at compile time, i.e. to call the generic CreateInstance you need to write something like the following (using Foo as the type argument).

Foo foo = Activator.CreateInstance<Foo>();

There are many scenarios where the type argument is not known at compile time, and in such cases System.Type is the way to go.

In case of the Activator, there are actually not that many scenarios when the type argument is known at compile time. If you know that the type argument is Foo, why not just use the Foo’s constructor?

Foo foo = new Foo();

Well, there are some reasons for having Activator.CreateInstace<T> (otherwise we would not have added it), but the scenarios are very rare. Imagine that you have a method that already has a type parameter corresponding to the type that needs to be constructed and the constructor to be invoked takes a parameter:

public static bool StrangeEquals<T>(T instance, params object[] args){
return Activator.CreateInstance<T>(args)).Equals(instance);
}

In this scenario, calling the constructor is not possible because our constraint system does not let you specify that a type argument needs a parameterized constructor. The StranceEquals method could of course use Reflection to invoke the constructor, but Activator.CreateInstace<T> is slightly more convenient.

Now, what about the parameterless CreateInstance<T>? Isn’t is equivalent to saying “new T()”? Yes, in fact the C# complier used Activator.CreateInstance<T> to implement “new T()”. The following code:

static object Bar<T>() where T:new() {
return new T();
}

Gets expanded by the compiler to:

private static object Bar<T>() where T: new() {
return ((default(T) == null) ? Activator.CreateInstance<T>() : default(T));
}

Comments

  • Anonymous
    November 17, 2005
    The comment has been removed
  • Anonymous
    November 17, 2005
    I've used the Activator.CreateInstance<T>() method in class that takes in a System.Data.IDataReader and creates an object of the correct type based on a O/R mapping.

    The method was something like this:

    public sealed class EntityFactory
    {
    public T CreateEntity<T>(IDataReader reader) where T: new()
    {
    T t = Activator.CreateInstance<T>();
    // Do the mapping
    return t;
    }
    }

    For me, the caller of this method knows the type it tries to create at compile time, so it matches my need perfectly.

    Person p = EntityFactory.CreateEntity<Person>(personReader);
  • Anonymous
    November 17, 2005
    The comment has been removed
  • Anonymous
    November 18, 2005
    The comment has been removed
  • Anonymous
    November 18, 2005
    The comment has been removed
  • Anonymous
    November 22, 2005
    Krzysztof,

    IMHO, This is too late to check if contructed object has correct type after contruction was complete.
  • Anonymous
    November 22, 2005
    P.S> Create(typeof(Bar)) is simply subset of my proposal - Create<object>(typeof(Bar)) will do same trick with "is/as"

  • Anonymous
    December 14, 2005
    So TAG, it seems you want something like this:

    T CreateInstance<T>(string typeName)
    where T : new()
    {
    Type desiredType = typeof(T);
    Type actualType = Type.GetType(typeName);

    if (!desiredType.IsAssignableFrom(actualType))
    throw YouDirtyRatException();

    return new T();
    }

    object CreateInstance( string typeName, Type desiredType)
    {
    Type actualType = Type.GetType(typeName);

    if (!desiredType.IsAssignableFrom(actualType))
    throw YouDirtyRatException();

    return Activator.CreateInstance(actualType);
    }

    ...which seems pretty easy to implement yourself...
  • Anonymous
    August 30, 2006
    The comment has been removed