【问题标题】:Anonymous Method with variable number of argument parameters具有可变数量参数参数的匿名方法
【发布时间】:2016-02-02 20:59:45
【问题描述】:

我正在尝试创建一个带有参数的 func 的扩展方法。我想支持可变数量的参数(无、1、2、...10)

我有这样的东西,恰好适用于三个参数。 如何简化它以支持可变数量的参数,而不必为每个排列复制和粘贴?有可能吗?

(注意:我的示例非常简单。我的实际实现有更多逻辑,例如支持具有计数、Thread.Sleep、跟踪日志记录、异常处理等的“重试”逻辑)

谢谢!

public static class UtilExtensions
{
    public static TResult Execute<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> function, T1 argument1, T2 argument2, T3 argument3))
    {
        // do other stuff ... like logging

        try
        {
           // call our 'action'
           TResult result = function(argument1, argument2, argument3);
           return result;
        }
        catch (Exception ex)
        {
           // do other stuff ... like logging, handle Retry logic, etc.
        }
    }
}

它是这样调用的:

public string DoSomething(int arg1, string arg2, MyObject arg3)
{
    if (arg1 == 1)
        throw new Exception("I threw an exception");

    return "I ran successfully";
}
public string DoSomethingElse()
{
    return "blah blah blah";
}

public string DoSomethingMore(DateTime dt)
{
    return "hi mom";
}


[TestMethod]
public void Should_call_UtilsExtensions_Execute_method_successfully()
{
    int p1 = 0;
    string p2 = "Hello";
    MyObject p3 = new MyObject();

    string results = UtilExtensions.Execute<int, string, MyObject, string>(
        DoSomething, p1, p2, p3);

    // ??? So how would I use my UtilExtensions api to call
    // DoSomethingElse (no arguments)
    // DoSomethingMore (one argument)
    // I'm okay to create overloads of my Execute method
    // but I don't want to copy-and-paste the same code/logic in each method

    results.Should().Be("I ran successfully");
}

【问题讨论】:

  • 如果我理解正确你想要的是类似于 C++ 可变参数模板的东西。看看这个答案:stackoverflow.com/questions/6844890/…
  • @李·泰勒。我不认为 params 会起作用......但如果你能告诉我其他方式,我会很高兴。
  • 我相信如果你放弃强类型化并在 System.Delegate 上创建扩展方法,params 会起作用
  • @Raymond - 请解释为什么你认为params 行不通

标签: c# lambda anonymous-function func


【解决方案1】:

我认为您无法做到这一点,据我所知,这正是 Func 和 Action 类型在 .Net 中针对不同参数编号有许多不同声明的原因。见https://msdn.microsoft.com/en-us/library/018hxwa8(v=vs.110).aspx左侧

除了在这种情况下,OP 询问的是接口Can I have a variable number of generic parameters?

问题本质上与泛型的基本限制相同。

您也许可以通过反射来做一些事情,但我认为您最好选择合理数量的参数来支持和编写重载。

Params 不起作用,因为对于 params,数组中的所有类型都是相同的类型。 T1、T2 等是供您使用的不同类型。您必须将参数声明为 Object[] ,这完全违背了泛型的意义。尽管如果您确实有未知数量的可能高得不切实际的参数,也许您愿意放弃类型检查。

【讨论】:

  • 谢谢,我就是这么想的……也许是时候使用代码生成器了。
  • @Raymond 是的,我以前见过一个用于此目的的代码生成器。感觉很脏,但实际上可能是最好的解决方案。只要您考虑了其他可能解决方案的影响并决定这对这种情况来说是最好的,那么我认为没关系。
【解决方案2】:

你不能那样做。另一种方法是创建一个接受一个参数的扩展方法,但该参数可以由匿名函数组成。因此,您的调用代码将完全控制如何使用它。不是最干净的,但至少比代码生成器路线更干净一点:

public static class UtilExtensions
{
    public static TResult Execute<TResult>(this Func<TResult> function)
    {
        // do logging

        try
        {
            TResult result = function();
            return result;
        }
        catch (Exception ex)
        {
            // do other stuff ... like logging, handle Retry logic, etc.
        }

        // or throw - this right here could prove unpredictable and is verrrry dirty
        return default(TResult);
    }
}

用法:

var param1 = 1;
var param2 = "string";

Func<bool> function = () => 
{
    // do stuff with param1 and param2
    return true;
}

var results = function.Execute();

【讨论】:

  • 我真的很喜欢这种方法,也是我最终使用的方法......但是,我仍然不得不复制并粘贴我的代码 4 次。 Action vs Func 各一个,异步方法支持又一个。我可能仍然会考虑使用代码生成的方法。
  • @Raymond 是的,我想你必须基本上重复代码 4 次 - 想不出办法解决这个问题。虽然......该代码将位于同一个地方并且之后几乎没有理由改变。我很想知道代码生成的方法最终是否值得花时间努力。
猜你喜欢
  • 1970-01-01
  • 2018-07-04
  • 1970-01-01
  • 2018-06-21
  • 1970-01-01
  • 2015-06-27
  • 2013-01-29
  • 1970-01-01
相关资源
最近更新 更多