tags:

views:

354

answers:

4

I'm trying to build a factory method that uses the generics feature of C#.

In this factory method I would like to constraint it to some specific classes, all of which do not have a default constructor.

Here is my example. Can someone tell me if it's possible to run it?

public class AbstractClass {
    //this abstract class does not have a default constructor, nor its subclasses
    public AbstractClass(SomeClassName obj) {
        //use obj for initialization
    }
}

//this factory class should create objects of type T that inherit 
//from AbstractClass and invoke the non-default constructor
public class FactoryClass {
    public static T BuildObject<T> (SomeClassName obj) where T: AbstractClass {
        return new T(obj); //does not work?!?!?!
    }
}


//Edit: ANSWER!!!
public static T BuildObject<T>(SomeClassUsedForTheConstructor item) where T : SomeAbstractClass { 
return (T) Activator.CreateInstance(typeof (T), item); 
}
+3  A: 

No, what you are trying to do is not possible using the built-in generic constraints alone. The new keyword only allows you to constrain the generic type to having a default constructor.

Mark Seemann
and only if T : new() is defined.
csharptest.net
+2  A: 

Look at the Type class and GetConstructor. Once you get the ConstructorInfo object, use the Invoke Method.

var x = typeof(T);
var t = x.GetConstructor(new[] {obj.GetType()});
object u = t.Invoke(<inputs>);
Chris J
This is what I used to use, but now I use `Activator.CreateInstance` as mentioned by Brian.
280Z28
+2  A: 

I don't think you can instantiate generic types without a default constructor on the constraint type.

Consider instead specifying an interface IAbstractClass, such that your factory class can set the SomeClassName parameter as a property of IAbstractClass.

Additionally, if a SomeClassName instance is required for initializing AbstractClass, consider also having an empty default constructor, but a rich initializer method defined in IAbstractClass. For example:

public interface IAbstractClass { void Initialize(SomeClassName obj); }

That way, your static BuildObject method instead does:

public static T BuildObject<T>(SomeClassName obj) where T: AbstractClass 
{
  T newObject = new T();
  IAbstractClass ac = newObject as IAbstractClass;
  ac.Initialize(obj);
}
emptyset
+2  A: 

I like to use Activator.CreateInstance(typeof(T)) in my generics that need to create new objects of type T. It works really well.

Brian Genisio
This should go into the .net rocks podcast! thanks for the answer.
pablo
//final code public static T BuildObject<T>(SomeClassUsedForTheConstructor item) where T : SomeAbstractClass { return (T) Activator.CreateInstance(typeof (T), item); }
pablo
It's slow and there's no compile-time checking...
Mark Seemann