简体   繁体   中英

Generics: When to use new() as a constraint of Type Parameters?

The type argument must have a public parameterless constructor. When used together with other constraints, the new() constraint must be specified last.

Can you guys give me a sample scenario when this constraint is needed?

This is essentially what the new() constraint boils down to:

class Factory<T> where T : new()
{
    public T Create()
    {
        return new T();
        //     ^^^^^^^
        //     this requires the new() type constraint.
    }
}

Now, you're not allowed to pass arguments to the constructor. If you nevertheless want to initialize the newed object, you could achieve this eg by introducing a further constraint:

interface ILikeBananas
{
    double GreenBananaPreferenceFactor { get; set; }
}

class Factory<T> where T : ILikeBananas, new()
{
    public T Create(double greenBananaPreferenceFactor)
    {
        ILikeBananas result = new T();
        result.GreenBananaPreferenceFactor = greenBananaPreferenceFactor;

        return (T)result;
        //     ^^^^^^^^^
        //     freely converting between ILikeBananas and T is permitted
        //     only because of the interface constraint.
    }
}

Note that another way of instantiating an object is via Activator.CreateInstance , which gives you some more freedom, such as passing arguments directly to a constructor.

Activator.CreateInstance does not strictly require the new() constraint; however, the type being instantiated still needs to provide a suitable constructor.

It's seldom needed in the sense of being the only way of accomplishing something. But sometimes it's the easiest way to do something.

For example let's say you're writing an object pool. When someone wants to take an object from the pool, it either returns an existing object or simply creates a new one if none is available. You could add the where T : new() constraint to allow yourself to simply write return new T(); .

The constraint isn't needed here, as you could've accomplished the same thing by taking a Func<T> in the pool's constructor and using that. Arguably, this method is in fact better, as it's more flexible. But again, new T() is just nice and easy.

I'll just drop in a simple example. I've created a method:

public T GetFromXml<T>(string xml)
    where T: class, new()
{
    if (String.IsNullOrEmpty(xml))
    {
        return new T();
    }
    return xml.AsObjectFromXml<T>();
}

And use it like this:

Phones = GetFromXml<List<PhoneData>>(source.Phones);

Because I prefer empty collections over null values.

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