views:

284

answers:

4

This isn't legal:

public class MyBaseClass
{
  public MyBaseClass() {}
  public MyBaseClass(object arg) {}
}


public void ThisIsANoNo<T>() where T : MyBaseClass
{
  T foo = new T("whoops!");
}

In order to do this, you have to do some reflection on the type object for T or you have to use Activator.CreateInstance. Both are pretty nasty. Is there a better way?

A: 
where T : MyBaseClass, new()

only works w/ parameterless public constructor. beyond that, back to activator.CreateInstance (which really isn't THAT bad).

Darren Kopp
not in a generic way.
Darren Kopp
+2  A: 

Nope. If you weren't passing in parameters, then you could constrain your type param to require a parameterless constructor. But, if you need to pass arguments you are out of luck.

Abe Heidebrecht
A: 

I can see that not working.

But what is stopping you from doing this?

public void ThisIsANoNo<T>() where T : MyBaseClass
{
  MyBaseClass foo = new MyBaseClass("whoops!");
}

Since everything is going to inherit from MyBaseClass they will al be MyBaseClass, right?

I tried it and this works.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            ThisIsANoNo<MyClass>();
            ThisIsANoNo<MyBaseClass>();
        }

        public class MyBaseClass
        {
            public MyBaseClass() { }
            public MyBaseClass(object arg) { }
        }

        public class MyClass :MyBaseClass
        {
            public MyClass() { }
            public MyClass(object arg, Object arg2) { }
        }

        public static void ThisIsANoNo<T>() where T : MyBaseClass
        {
            MyBaseClass foo = new MyBaseClass("whoops!");
        }
    }
}
chrissie1
What happens if you have a derived class that only has a constructor that takes 2 arguments?
Abe Heidebrecht
This method will never return objects of type T, only objects of type MyBaseClass.
Matt Howells
it's a void it's not returning anything. and a cast can fix that.
chrissie1
@Abe I tried it and it works.
chrissie1
T is an extension of MyBaseClass. You can new up an instance of MyBaseClass, but you cannot "up-cast" it to T, because it is not a T. In addition, your ThisIsANoNo implementation, while it has a generic signature, does not new up an instance of the type variable.
Will
+1  A: 

You can't constrain T to have a particular constructor signature other than an empty constructor, but you can constrain T to have a factory method with the desired signature:

public abstract class MyBaseClass
{
    protected MyBaseClass() {}
    protected abstract MyBaseClass CreateFromObject(object arg);
}

public void ThisWorksButIsntGreat<T>() where T : MyBaseClass, new()
{
    T foo = new T().CreateFromObject("whoopee!") as T;
}

However, I would suggest perhaps using a different creational pattern such as Abstract Factory for this scenario.

Matt Howells