2015-09-04 3 views
2

Я пытаюсь построить некоторые объекты в разумно общей форме. Некоторые из объектов имеют параметры конструктора, другие - нет.Передача и выполнение функций с различными сигнатурами параметров

То, что я пытаюсь достичь, - это вернуть какую-то функцию строителя, к которой я могу предоставить параметр конструктора, если это необходимо.

Я знаю, что у меня могут быть необязательные параметры переданные вниз, но в моем реальном сценарии есть несколько уровней, и я ненавижу добавлять необязательные параметры вниз по иерархии.

Я не слишком занимаюсь частичным применением/каррированием, но могу ли я использовать это здесь, и если да, то как?

Вот несколько примеров кода, который не сработает, чтобы попытаться объяснить немного больше того, что мне нужно.

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; 
    } 
} 

Многие ТНХ

S

+0

Если вам это удастся, отправьте свой код – netaholic

ответ

1

Вы должны использовать код отражения для обнаружения конструктор/метод с вами параметры и вызвать его.

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

~ Источник: Using C# reflection to call a constructor

альтернативы у вас есть класс MethodInfo, если вы должны использовать методы GetClassX

Подробнее

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

2

Электронная labate @Sylwekqaz, вы можете иметь что-то вроде ниже, а не ограничивать себя типом 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()); 
    } 
} 

И тогда вы можете позвонить строитель, как

var a = Builder.Build<ClassA>(); 
var b = Builder.Build<ClassB>(); // need parameterless ctor in ClassB 
var c = Builder.Build<ClassB>("param"); 
+1

Это очень приятно. –

1

Я не полностью следовать вашему примеру коды, но вы спрашиваете о частичном применении и выделке ...

Лучшим путь, который я нашел, - это просто создать N функций, которые берут из 1-N общих параметров, а затем позволить компилятору выбрать тот, который вы хотите. Если вы посмотрите на мой language-ext проекта У меня есть две функции, одна называется curry и один называется par для выделки и частичного применения:

Currying source

Partial application source

Для частичного применения, сделайте следующее:

// 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); 

Для карри, сделайте следующее:

// 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); 
Смежные вопросы