TheFabledOne
TheFabledOne

Reputation: 238

Possible to compile-time check constructor parameters for generic factory function?

I am experimenting with some factory type code where the BuildIt function returns a concrete type based solely on the generic type passed in. The generic type is restricted to being descendants of the BaseAbstract class.

The Buildit function just needs the generic type and then a list of params (the params are used as constructor parameters in the BuildIt function when creating the concrete classes).

The example code below works as expected (prints "A" then "B")

But the problem happens if I try to call something like:

        var b = fs.BuildIt<B>("B", "C");

Since the B class doesn't have a constructor with 2 parameters, this fails at runtime.

Is it possible to do something like this, except have this fail at compile time? If not, is there another way to go about this so that compile time checking is possible (doesn't matter if all this has to be thrown out and start something completely different)

Example Code

public abstract class BaseAbstract
{
    public string Name ="";
    public override string ToString ()
    {
        return Name;
    }
}

public class A : BaseAbstract
{
    public A()
    {
        Name = "A";
    }
}

public class B : BaseAbstract
{
    public B()
    {
    }

    public B(string param)
    {
        Name = param;
    }
}

public class Factory
{
    public T BuildIt<T>(params object[] args) where T : BaseAbstract, new()
    {
        T x = (T)Activator.CreateInstance(typeof(T), args);
        return x;
    }
}

public class MainClass
{
    public static void Main (string[] args)
    {
        //These are fine
        Factory fs = new Factory();
        var a = fs.BuildIt<A>();
        var b = fs.BuildIt<B>("B");
        Console.WriteLine (a);
        Console.WriteLine (b);

          //This would cause runtime error because of the "C" paramter
          //var b2 = fs.BuildIt<B>("B", "C");

    }
}

Upvotes: 3

Views: 899

Answers (1)

Haney
Haney

Reputation: 34742

Not really, since you're using reflection which is a runtime technology... The only way the compiler would become aware of the inability to create your instance would be to run your code... At least until the CAAS shows up.

One option might be to approach this differently: force a new() constraint on your generic type in the method (makes sure that all types have a parameterless constructor) and then maybe map the constructor parameters as properties instead on your types? Maybe not ideal if you want immutability but reflection can write to private types etc. anyway...

This is pretty much the kind of scenario that the ArgumentException class was built for... Throw it if stuff doesn't work as expected.

Upvotes: 2

Related Questions