2016-10-03 108 views
0

我无法防止重复的代码。委托传递为通用参数时调用C#委托方法

目前,我有以下方法:

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

不要这样做。如果在这两种方法中存在多余的重复代码,则将重复的代码抽象为辅助方法。但不要更改两个方法的签名,然后尝试在运行时强制实现类型系统。更一般地说:人们花费太多时间担心小的重复。正如你所发现的那样,它们的重复数据删除非常昂贵,而且这种努力可能会更好地用于编写测试,寻找错误,设计下一个版本等等。 –

+0

尝试使用Action <>? – lindexi

回答

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]; 
+0

这确实是可能的,但我们假设回调方法不能更改 – Brecht

+0

您将需要包装方法,但我不太喜欢这个想法。 (或者你需要一个完全不同的解决方案) –

+0

@Brecht,我的编辑可能会让你感兴趣,我也会回答如何打电话给你的代表;) –

1

不要让这种方法有责任接受将被传递到回调参数第一个地方。不要通过任何参数。如果调用者有一个他们想要在回调中使用的值,那么可以使用闭包关闭该变量。

这个对象不仅要接受任意数量的参数并将它们传入回调函数(并且不可能以类型安全的方式完全概括),而且调用方也很容易解决这个问题一个完全一般的情况和完全类型的安全方式,但是这些信息在逻辑上是调用者的私有实现细节,并不是该方法有任何理由首先要知道的信息。