我在防止重复代码方面遇到了问题。
目前我有这些方法:
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的方法。我错过了什么大事吗?
答案 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];