2016-02-02 34 views
2

我正在尝试创建一个带参数的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"); 
} 
+0

https://msdn.microsoft.com/en-us/library/w5zay9db.aspx –

+0

如果我理解正确,你想要的东西类似于C++ variadic模板。看看这个答案:http://stackoverflow.com/questions/6844890/simulate-variadic-templates-in-c-sharp –

+0

@李泰勒。我不认为params会起作用......但如果你能以其他方式展示我会很高兴。 – Raymond

回答

2

我不认为你可以做到这一点,因为据我所知,这正是Func键和动作类型有许多不同的声明的原因用于.Net中的不同参数编号。见https://msdn.microsoft.com/en-us/library/018hxwa8(v=vs.110).aspx

左手边你问类似下面的东西,除了在这种情况下,OP问的接口Can I have a variable number of generic parameters?

的问题基本上是仿制药相同的基本限制。

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

参数不起作用,因为对于参数,数组中的所有类型都是相同的类型。 T1,T2等是供您使用的不同类型。你必须将参数声明为Object [],这完全击败了泛型。虽然也许你愿意放弃类型检查,如果你真的有一个未知数量的参数可能不切实际的高。

+0

谢谢,这就是我的想法......也许是代码生成器的时候了。 – Raymond

+0

@Raymond是的我以前见过用于这个确切目的的代码生成器。它感觉肮脏,但实际上可能是最好的解决方案。只要你考虑过其他可能的解决方案的意义,并且认为这对于这种情况是最好的,那么我认为它是可以的。 –

1

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

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(); 
+0

我真的很喜欢这种方法,并且是我最终使用的......但是,我仍然需要复制并粘贴我的代码4次。其中一个用于Action vs Func ,另一个用于异步方法支持。我仍然可以考虑采用代码生成的方法。 – Raymond

+0

@Raymond是的,我猜想你必须重复代码基本上4次 - 想不到一个方法。尽管......代码会坐在同一个地方,之后没有什么理由变化。我很想知道一个代码生成的方法是否值得花费时间。 – Balah