简体   繁体   English

传递和执行具有不同参数签名的函数

[英]Passing and executing functions with different parameter signatures

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? 我不太关注部分应用程序/ currying,但是我可以在这里使用它吗?如果可以,如何使用?

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 小号

To elaborate @Sylwekqaz you could have something like below, and not restrict yourself for type of BaseClass . 要详细说明@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());
    } 
}

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

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 〜source: 使用C#反射调用构造函数

alternatively you have a class MethodInfo if you must use methods GetClassX 或者,如果必须使用方法GetClassX,则有一个MethodInfo类

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.type.getconstructor%28v=vs.110%29.aspx

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

I don't entirely follow your code example, but you ask about partial-application and currying... 我不完全遵循您的代码示例,但是您询问部分应用程序和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. 我发现最好的方法是只创建从1-N个通用参数中提取的N个函数,然后让编译器选择所需的函数。 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: 如果您看一下我的language-ext项目,我有两个函数,一个叫做curry ,另一个叫做par用于currying和部分应用:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 重构方法调用具有不同参数签名的代理 - Refactor methods invoking delgates with different parameter signatures 减少代码重复:调用具有略微不同签名的函数 - Reducing Code Repetition: Calling functions with slightly different signatures 模拟具有不同签名的方法,其中一个具有Object作为参数类型 - Mocking a method with different signatures where one has Object as a parameter type 从接收委托类型参数的方法中调用具有不同签名的方法 - Calling methods with different signatures from a method that receives a delegate type parameter 在不同阶段执行嵌套的异步函数 - Executing nested async functions at different stages 具有相似但不相同签名的函数的包装 - Wrapper for functions with similar but not identical signatures 将方法调用及其参数传递给其他方法 - Passing a method call and its parameter to a different method 在命令参数Wpf中传递其他按钮 - Passing a Different button in Command Parameter Wpf 将具有预定义结构的列表作为参数传递给其他表单 - Passing a List, with a predefined structure, as parameter to a different Form 将参数传递给不同视图之间的显示模板 - Passing parameter to displaytemplate between different views
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM