[英]I am new to delegates and wonder how to break down the following code
我有以下代碼,我想知道如何分解它? 它工作得很好,但是是由一位大師寫的並且超出了我的想象。 預先感謝您的任何幫助。
該代碼基本上將發送和接收的設備信息寫入GUI。 看起來它有基於設備創建的事件,並且還調用GUI內容。
公共事件EventHandler CommunicationPerformed = delegate {};
SerialPort _port;
readonly int _delay = 100;
private string ReadAndUpdateStatus()
{
string read = _port.ReadExisting();
CommunicationPerformed?.Invoke(this, new LoaderReadWriteEventArgs(read, LoaderCommunicationDirection.Read));
return read;
}
private void WriteAndUpdateStatus(string data)
{
if (!data.StartsWith("//")) //ignore "Comment" lines but show them on the GUI to read
_port.Write(data);
CommunicationPerformed?.Invoke(this, new LoaderReadWriteEventArgs(data, LoaderCommunicationDirection.Write));
}
public class LoaderReadWriteEventArgs : EventArgs
{
public LoaderCommunicationDirection Direction { get; }
public string Value { get; }
public LoaderReadWriteEventArgs(string value, LoaderCommunicationDirection direction)
{
Value = value;
Direction = direction;
}
}
public enum LoaderCommunicationDirection
{
Read,
Write
}
你問了三個問題,和往常一樣,只有一個問題得到了回答。 試着在你的問題中只問一個問題。
我也想知道
delegate { }
是什么?public event EventHandler CommunicationPerformed = delegate { };
正如另一個答案所指出的,默認情況下C#中的事件為空。 此技術使事件處理程序不執行任何操作 ,但不為null 。
遺憾的是,C#中的匿名函數有許多語法。 delegate {}
表示“給我一個無用的函數,匹配任何返回無效的非ref-out形式參數列表”。 這就是人們delegate{}
的原因,因為它幾乎可以在需要事件處理程序的上下文中工作。
我想你需要查看這個https://docs.microsoft.com/en-us/dotnet/standard/events/ 。
你為什么需要調用?
向廣播事件處理程序廣播(注冊此事件的任何一方都會收到通知)
我想我想知道這是否過於復雜或合適?
*完成相同任務可能是更好的方法嗎?
這並不復雜。 這非常簡單。*
我也想知道“代表{};” 呢?
我的兩分錢。 我不知道您引用的是哪個代碼行,但委托是一種包含對方法的引用的類型。 委托聲明帶有簽名,該簽名顯示它引用的方法的返回類型和參數,並且只能保存對與其簽名匹配的方法的引用。 因此委托等同於類型安全函數指針或回調。 委托聲明足以定義委托類。
我要嘗試回答#1和#2(已經覆蓋了3個)。
#1 - 在某些時候,某人決定該程序的其他部分可以訂閱一個事件,告訴他們何時進行了通信。 一旦做出決定,這就是一種“合同”。 您執行通信 - >觸發事件,通知訂閱者已執行通信。 那些訂閱者正在做些什么,或者為什么他們需要知道......如果這個課程是你的重點,那么你真的不關心。 從理論上講,至少。 而且通常情況確實如此。 如果你的班級正在做自己的工作,那么聽你們關注這些事件並不是你真正關心的問題。
#2 - 我想聲明的事件和事件處理程序在你的代碼的方法過於復雜。 很多人(以及微軟的官方最佳實踐 )都不同意我的意見。 你可以谷歌“為什么我的事件處理程序應該使用eventargs”並閱讀有關該主題的大量內容。 或者看這里 另一種方法如下:
public event Action<string, LoaderCommunicationDirection> CommunicationPerformed;
void PerformWrite()
{
string myComm = "String I'm sending";
//Line of code that performs communication that writes string here
CommunicationPerformed?.Invoke(myComm, LoaderCommunicationDirection.Write);
}
這比從EventArgs
派生的整個類簡潔得多。 但是,它有一個非常明顯的缺點,如果你是一個事件訂閱者...你不知道什么是string
。 當然,因為它在你的代碼中被命名為value
...這沒有多大幫助。 事件聲明上方的評論幾乎同樣有用。
orhtej2很好地回答了你的第一個問題。 使用顯式的Invoke方法允許您利用null條件運算符,這會減少代碼以將事件觸發到一行。
至於這是否過於復雜:不,這基本上是事件的完成方式。
我有時看到的(尤其是與MVVM模式中的INotifyPropertyChanged接口結合使用)是輔助方法,它封裝了更長但更明顯的前C#6代碼,讓您以更少的管道激活事件。
private void FireCommPerformed(string value, LoaderCommunicationDirection direction)
{
EventHandler handler = CommunicationPerformed;
if (handler != null)
{
handler(this, new LoaderReadWriteEventArgs(value, direction)));
}
}
然后你可以像這樣使用它:
private string ReadAndUpdateStatus()
{
string read = _port.ReadExisting();
FireCommPerformed(read, LoaderCommunicationDirection.Read);
return read;
}
Delegate {}只是一個空委托,就像事件的null一樣。 除非代碼中的某些其他方法在運行時期間訂閱此類的CommunicationPerformed事件,否則在觸發事件時不會發生任何事情。
讓我們專注於這里發生的事情。 這應該可以幫助你弄清楚其他一切。
CommunicationPerformed?.Invoke(this, new LoaderReadWriteEventArgs(read, LoaderCommunicationDirection.Read));
這是檢查委托(事件處理程序是委托)(CommunicationPerformed)是否為空。
代表是指針(但具有額外的功能)。
如果委托(指針)為空,則表示沒有為其分配任何內容。
指針存儲內存位置。 在這種情況下,它會對函數'this'進行內存引用。 'this'是對ReadAndUpdateStatus()的引用。
所以這一行基本上說:“因為指針為空,所以讓這個指針引用ReadAndUpdateStatus()函數”。
但事件args怎么樣? 嗯......這是代表們與指針不同的地方。
代表們不僅可以安全地保存和存儲內存位置。 它們也可以保存參數。
您使用從EventArgs擴展的類作為傳遞參數列表的方式。
從這里開始,事件處理程序(事件處理程序是委托)CommunicationPerformed將協調將參數列表發送到任何需要它的函數。
每當調用CommunicationPerformed時(例如告訴運行),都會調用這些函數。 這通常表示為:
+=CommunicationPerformed(foo,bar)
現在 - 為什么要使用事件處理程序(或任何委托 - 就此而言)?
他們閱讀比較繁瑣煩人(比編寫一個簡單的bool和觸發器功能更多的工作),它們看起來不像其他功能,而且它們很坦白 - 對吧?
除了他們真的有用。 這是如何做:
1.)他們的工作很像任務。 您可以在並行,循環,任何地方調用它們。 他們保持一致的狀態。 它們不會“流血”並導致錯誤。
2.)他們是指針。 保證傳遞參考。 除此之外,它們是神奇的,如果你停止使用代表,它們就不會留在記憶中。
3.)它們允許您控制循環中的狀態。 有時,如果你處於一個非常緊湊的循環中,bool觸發器將無法正常工作。 你開了一個活動? 保證您的觸發器只會被觸發一次的行為。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.