【问题标题】:Passing and executing functions with different parameter signatures传递和执行具有不同参数签名的函数
【发布时间】:2015-11-30 09:37:31
【问题描述】:

我正在尝试以一种相当通用的方式构造一些对象。有些对象有构造函数参数,有些则没有。

我想要实现的是返回某种构建器函数,如果需要,我可以向其提供构造函数参数。

我知道我可以传递可选参数,但在我的实际场景中,有几个层,我不愿意在层次结构中添加可选参数。

我对部分应用程序/currying 不太感兴趣,但我可以在这里使用它吗?如果可以,如何使用?

这里有一些示例代码 - 不起作用 - 尝试更多地解释我所追求的。

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

【问题讨论】:

  • 如果你能做到,请发布你的代码

标签: c# generics functional-programming currying


【解决方案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

如果您必须使用 GetClassX 方法,或者您有一个类 MethodInfo

更多信息

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】:

    要详细说明@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");
    

    【讨论】:

      【解决方案3】:

      我不完全遵循您的代码示例,但是您询问了部分应用程序和柯里化...

      我发现的最好方法是创建 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);
      

      【讨论】:

        猜你喜欢
        • 2018-01-10
        • 2020-09-13
        • 2022-01-10
        • 2018-02-07
        • 2018-06-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多