2

I am trying to construct some objects in a reasonably generic way. Some of the objects have constructor params, others don't.

What I am trying to achieve is to return some kind of builder function to which I can supply the constructor param if required.

I know I could have optional params passed down, but in my real scenario, there are several layers and I'm loathed to add optional params down the hierarchy.

I'm not too up on partial application/currying, but could I use that here and if so, how?

Here's a bit of sample code - which won't work - to try and explain a bit more what I'm after.

public void Main()
{
    dynamic buildClass = ClassBuilder<BaseClass>(true);
    // ideally I'd like to be able to supply the constructor data 
    // here
    var theClass = buildClass(???)

} 

public Func<???, TClass> ClassBuilder<TClass>(bool flag) where TClass : BaseClass
{
    // obviously this won't work since the delegates have different
    // signatures
    if (flag) return () => GetClassA();
    return (x) => GetClassB(x);
}


public object GetClassA()
{
    return new ClassA();
}

public object GetClassB(string param)
{
    return new ClassB(param);
}

public class BaseClass {}

public class ClassA : BaseClass {}

public class ClassB : BaseClass
{
    private string _param;
    public ClassB(string param)
    {
        _param = param;
    }
}

Many thx

S

Simon Woods
  • 905
  • 1
  • 6
  • 13

3 Answers3

2

To elaborate @Sylwekqaz you could have something like below, and not restrict yourself for type of BaseClass.

public static class Builder
{
    public static T Build<T>(params object[] args) where T : class
    {
        var info = typeof(T).GetConstructor(args.Select(arg => arg.GetType()).ToArray());
        if (info == null)
            throw new ArgumentException(@"Can't get constructor :(", "args");

        return (T)info.Invoke(args.ToArray());
    } 
}

And then you can call your builder as

var a = Builder.Build<ClassA>();
var b = Builder.Build<ClassB>(); // need parameterless ctor in ClassB
var c = Builder.Build<ClassB>("param");
Mikko Viitala
  • 8,344
  • 4
  • 37
  • 62
1

You must use code reflection to detect constructor/method with you parameters and invoke it.

Type type = typeof(YourClass);
ConstructorInfo ctor = type.GetConstructor(new[] { typeof(string) });
object instance = ctor.Invoke(new object[] { 10 });

~source: Using C# reflection to call a constructor

alternatively you have a class MethodInfo if you must use methods GetClassX

More info

https://msdn.microsoft.com/en-us/library/system.type.getconstructor%28v=vs.110%29.aspx

https://msdn.microsoft.com/en-us/library/system.reflection.constructorinfo.invoke%28v=vs.110%29.aspx

Community
  • 1
  • 1
Sylwekqaz
  • 329
  • 2
  • 9
1

I don't entirely follow your code example, but you ask about partial-application and currying...

The best way I've found is to just create N functions that take from 1-N generic parameters, then let the compiler pick the one you want. If you take a look at my language-ext project I have two functions, one called curry and one called par for currying and partial application:

Currying source

Partial application source

To partially apply, do this:

// Example function
int AddFour(int a,int b,int c, int d)
{
    return a + b + c + d;
}

// This returns a Func<int,int,int> with the first two arguments 10 & 5 auto-provided
var tenfive = par(AddFour, 10, 5);

// res = 10 + 5 + 1 + 2
var res = tenfive(1,2);

To curry, do this:

// Example function
int AddFour(int a,int b,int c, int d)
{
    return a + b + c + d;
}

// Returns Func<int,Func<int,Func<int,Func<int,int>>>>
var f = curry(AddFour);

// res = 10 + 5 + 1 + 2
var res = f(10)(5)(1)(2);
louthster
  • 1,560
  • 9
  • 20