简体   繁体   中英

Create a new instance of T without the new constraint

If one wants to create a new instance of a generic, the new constraint needs to be defined, like so:

public T SomeMethod<T>() where T : new()
{
    return new T();
}

Is it possible, using reflection, to create an instance of T without the new constraint, like so (contains pseudocode):

public T SomeMethod<T>()
{
    if (T has a default constructor)
    {
        return a new instance of T;
    }
    else
    {
        return Factory<T>.CreateNew();
    }
}

Use Activator.CreateInstance() for this. See http://msdn.microsoft.com/en-us/library/system.activator.createinstance.aspx for more information on how to use this method. Basically, what you do is:

var obj = (T)Activator.CreateInstance(typeof(T));

You can verify whether it has a default constructor by using the GetConstructors() method:

var constructors = typeof(T).GetConstructors();

If you find a constructor that has zero parameters, you can use the Activator.CreateInstance method. Otherwise, you use the Factory<T>.CreateNew() method.

EDIT:

To find out directly whether a constructor without any parameters exist, you can use the following check:

if (typeof(T).GetConstructor(Type.EmptyTypes) != null)
{
    // ...

Generic methods with a where T : new() constraint implement new T() calls by invoking Activator.CreateInstance<T>() . One interesting thing about this method is that it doesn't include the constraint , so if you are happy to defer the check until runtime, just use:

public T SomeMethod<T>() {
    return Activator.CreateInstance<T>();
}

which will either do exactly what return new T() would have done, or will raise a meaningful exception. Because it handles both the success and failure case, there is no real benefit in doing any additional checks, unless you wanted to do something obscure like not using a constructor at all (which can be done).

The last sentence from Marc Gravell's answer (emphasis mine)

...unless you wanted to do something obscure like not using a constructor at all ( which can be done )

and from this comment of his, there is an alternative to achieve the same thing. I don't much know which is better performance wise , but honestly, I don't care. If you want to know, follow that link. There author shows a hybrid way.

Use System.Runtime.Serialization.FormatterServices.GetUninitializedObject() (old MSDN documentation link ).

public static T SomeMethod<T>()
{
    if (typeof(T) == typeof(string))
    {
        return default(T);
    }

    return (T)FormatterServices.GetUninitializedObject(typeof(T));
}

Note the special care for string . Without that GetUninitializedObject() would fail. This is from MSDN on using this approach on strings:

It does not create an uninitialized string, since creating an empty instance of an immutable type serves no purpose.

It says nothing about why it fails , but more about why it should fail . Immediately after this there is another Note which goes like this:

You cannot use the GetUninitializedObject method to create instances of types that derive from the ContextBoundObject class.

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