回調用於爲服務器和客戶端之間提供異步的反饋,其中可能會涉及到多線程或者需要提供一個入口點用於同步更新,在C#中,我們使用委託來表達回調。
委託爲我們提供了類型安全的回調定義,雖然大多數常見的委託應用都和事件相關,但是那並不是委託應用的全部場合。當類之間有通信的需要,並且我們期望一種比接口更加松耦合的機制時,委託就是最合適的選擇。委託允許我們在運行時配置目標,並且可以通知多個對象,委託對象中包含一個方法引用,這個方法可以是靜態方法,也可以是實例方法。
我們還可以爲委託綁定多個方法,利用委託的多播機制,可以一次調用多個方法。但是有兩點需要注意:1)如果有委託調用出現異常,那麼這種構造將不能保證安全;2)整個多播調用的返回值是最後一個調用的方法的返回值。
在一個多播委託調用的過程中,每一個目標都會被順次調用,委託對象本身不會捕捉任何異常,因此,任何目標拋出的異常都會結束委託鏈的調用。
同樣,委託的返回值也有同樣的問題,如果委託的返回值類型不是void,那麼對於一個多播委託來說,最後的返回值就是委託鏈上執行的最後一個方法,其他的返回值都會被忽略。
我們來看下面的代碼。
public delegate bool ContinueProcessing();
public void LengthyOperation( ContinueProcessing pred )
{
foreach( ComplicatedClass cl in _container )
{
cl.DoLengthyOperation();
// Check for user abort:
if (false == pred())
return;
}
}
//Test
ContinueProcessing cp = new ContinueProcessing ( CheckWithUser );
cp += new ContinueProcessing( CheckWithSystem );
c.LengthyOperation( cp );
上述代碼在執行過程中,就會忽略CheckWithUser()方法的返回值。
我們可以自己手動遍歷委託鏈來解決這個問題,來看下面的代碼。
public delegate bool ContinueProcessing();
public void LengthyOperation( ContinueProcessing pred )
{
bool bContinue = true;
foreach( ComplicatedClass cl in _container )
{
cl.DoLengthyOperation();
foreach( ContinueProcessing pr in pred.GetInvocationList( ))
bContinue &= pr();
if (false == bContinue)
return;
}
}
上述代碼中,我們調用GetInvocationList()方法來手動遍歷委託鏈,這樣就可以解決上面提到的CheckWithUser()方法返回值被忽略的問題。
委託爲我們提供了一種在運行時進行回調的最好方式,這種方式對客戶類只有非常簡單的要求,我們可以在運行時配置委託目標。另外,委託也支持多播,在.NET中,我們應該使用委託的方式來實現回調。