委托作为Generic Argument传递时调用C#Delegate方法

时间:2016-10-03 13:41:39

标签: c# generics delegates

我在防止重复代码方面遇到了问题。

目前我有这些方法:

protected delegate bool CallbackDelegate<T>(T param, out string result);
protected delegate bool CallbackDelegate<T, U>(T param1, U param2, out string result);

protected bool ClientCtrlCallback<T>(T param, CallbackDelegate<T> callbackMethod)
{...}
protected bool ClientCtrlCallback<T,U>(T param1, U param2, CallbackDelegate<T,U> callbackMethod)
{...}

两个ClientCtrlCallback方法都具有相同的代码(检查通信通道的有效性,try-catch块,获取锁等)围绕CallbackDelegate方法的调用。

我一直在尝试合并这些ClientCtrl方法,但没有成功,因为不允许委托约束。这是我得到的:(为清晰起见,删除了不必要的代码)

protected delegate bool CallbackDelegate1<T>(T param, out string result);
protected delegate bool CallbackDelegate2<T, U>(T param1, U param2, out string result);
protected const string METHOD_MY_DELEGATE1 = "CallbackDelegate1";
protected const string METHOD_MY_DELEGATE2 = "CallbackDelegate2";
protected interface ParameterSet { };
protected class OneParameter<T>: ParameterSet { public T p1; };
protected class TwoParameters<T,U> : ParameterSet { public T p1; public U p2; };

protected bool ClientCtrlCallback<D,T,U>(ParameterSet parameterset, D callbackMethod, string successLog = null) // where MyDelegate : delegate  //not allowed
{
  // delegate constrained is not allowed, so check it here
  if (!typeof(D).IsSubclassOf(typeof(Delegate)))
    return false;

  // check name of method (this works)
  string methodName = (callbackMethod as Delegate).Method.Name;

  // Call the delegate // doesn't work.
  string result;
  switch (methodName)
  {
    case METHOD_MY_DELEGATE1:
      // doesnt work
      //(callbackMethod as Delegate)((parameterset as OneParameter<T>).p1, out result);
      break;

    case METHOD_MY_DELEGATE2:
      // doesnt work
      //(callbackMethod as Delegate)((parameterset as TwoParameters<T, U>).p1, (parameterset as TwoParameters<T, U>).p2, out result); // doesnt work
      break;
  }
  return true;
}

参数类开始变得丑陋。切换比较代表的名字会变得更糟(我也不喜欢每个人给他们一个不同的名字)。当我想调用Delegate的方法时,总是遇到麻烦:编译时错误Method name expected

我不明白为什么我可以从Delegate获取方法名,但不能调用Delegate的方法。我错过了什么大事吗?

2 个答案:

答案 0 :(得分:1)

不要让这个方法负责接受将首先传递给回调的参数。不要传递任何参数。如果调用者有一个他们想要在回调中使用的值,那么可以使用闭包来关闭该变量。

这个对象不仅非常难以接受任意数量的参数并将它们传递给回调(并且不可能以类型安全的方式完全推广),并且对于调用者来说也很容易解决这个问题。完全一般的情况和完全类型安全的方式,但该信息在逻辑上是调用者的私人实现细节,并且该方法首先没有任何理由知道该信息。

答案 1 :(得分:0)

<强> EDITED
你能不能拥有:

protected delegate bool CallbackDelegate<TParameterSet>(TParameterSet param, out string result)
    where TParameterSet : ParameterSet;

然后(现在似乎不太有用,取决于你的其余代码):

protected bool ClientCtrlCallback<TParameterSet>(TParameterSet parameterset, CallbackDelegate<TParameterSet> callbackMethod, string successLog = null)
    where TParameterSet : ParameterSet
{
    string result;
    return callbackMethod(parameterset, out result);
}

最后你的回调方法:

bool CallbackMethodOneParameter<T>(OneParameter<T> parameter, out string result)
{
    // Do your stuff with parameter.p1;
    // set result
    // return success or fail
}

bool CallbackMethodTwoParameters<T, U>(TwoParameters<T, U> parameters, out string result)
{
    // Do your stuff with parameters.p1 and parameters.p2;
    // set result
    // return success or fail
}

不再申请
我也想知道你是否真的需要在这里使用泛型。您的回调方法可能已经知道您的ParameterSet包含哪些类型 因为,使用此泛型,如果您需要另一个参数,则必须在此签名的任何位置进行更改。它会变得很痛苦。

在您的代码中,要调用您的代理人,您可以这样做:

var parameters = new object[] { (parameterset as OneParameter<T>).p1, null };
var success = (callbackMethod as Delegate).DynamicInvoke(parameters);
result = parameters[1];