學(xué)習(xí)C#的事件模式時(shí)Delegate和event這二個(gè)概念比較難理解,因?yàn)檫@二個(gè)都被設(shè)計(jì)成關(guān)鍵字,想進(jìn)一步查看其定義和實(shí)現(xiàn)就沒(méi)有下文了,不過(guò)再難也得硬著頭皮弄明白,我以前好長(zhǎng)時(shí)間都是似懂非懂的狀態(tài),后來(lái)在學(xué)習(xí)了觀察者設(shè)計(jì)模式和IL后利用這二者的知識(shí)來(lái)理解就比較容易。下面我就用觀察者設(shè)計(jì)模式和IL來(lái)分析一下事件模式中Delegate和event這二個(gè)關(guān)鍵字。
首先,我們來(lái)了解一下delegate究竟是什么東西,先來(lái)看一下下面的程序(為了演示,代碼盡量簡(jiǎn)略)。
Using System;
public class Test
{
public delegatevoid aaa();
public static void Main(String[]args) {
aaaa=new aaa(show);
a();
}
public static voidshow()
{
Console.WriteLine("hi");
}
}
以上代碼用csc.exe編譯后再用ILDASM反編譯成文本文件:
.class public auto ansibeforefieldinit Test extends [mscorlib]System.Object
{
.class auto ansisealed nestedpublicaaa extends[mscorlib]System.MulticastDelegate
{
.method public hidebysig specialnamertspecialname instance void .ctor(object 'object', native int'method') runtime managed
{
} // end of method aaa::.ctor
.method public hidebysig newslotvirtual instance void Invoke() runtime managed
{
} //end of method aaa::Invoke
.method public hidebysig newslotvirtual instance class[mscorlib]System.IAsyncResult BeginInvoke(class [mscorlib]System.AsyncCallback callback,
object 'object')runtime managed
{
} // end of method aaa::BeginInvoke
.method public hidebysig newslotvirtual instance void EndInvoke(class [mscorlib]System.IAsyncResultresult) runtime managed
{
} // end of method aaa::EndInvoke
} // end of class aaa
.method public hidebysig static void Main(string[] args) cil managed
{
.entrypoint
//
.maxstack 2
.locals init (class Test/aaa V_0)
IL_0000: nop
IL_0001: ldnull
//將show方法的指針推送到計(jì)算堆棧上
IL_0002: ldftn void Test::show()
IL_0008: newobj instance voidTest/aaa::.ctor(object,
native int)
IL_000d: stloc.0
IL_000e: ldloc.0
IL_000f: callvirt instance voidTest/aaa::Invoke()
IL_0014: nop
IL_0015: ret
} // end of method Test::Main
.method public hidebysig static void show() cil managed
{
//
.maxstack 8
IL_0000: nop
IL_0001: ldstr "hi"
IL_0006: call void[mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method Test::show
.method public hidebysig specialnamertspecialname
instance void .ctor() cil managed
{
//
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void[mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method Test::.ctor
} // end of class Test
從反編譯出來(lái)IL指令中可以看到delegate關(guān)鍵字修飾的aaa由編譯器轉(zhuǎn)換為一個(gè)繼承自System.MulticastDelegate的類,然后在main方法中以方法show的指針作參數(shù)構(gòu)造一個(gè)aaa的實(shí)例,后面再通過(guò)該實(shí)例調(diào)用Invoke方法,相信至此對(duì)delegate關(guān)鍵字應(yīng)該明白其作用了。
要了解事件模式的話,光是了解delegate還不夠,我們還得看看event是什么玩藝:
using System;
public class Test {
public static voidMain(String[] args) {
EventTest et = newEventTest();
et.OnPRopertyChanged+=show;
et.Age=2;
}
public static void show()
{
Console.WriteLine("event trigged");
}
}
public class EventTest
{
public delegate voidPropertyChangedHandler();
public eventPropertyChangedHandler OnPropertyChanged;
private int age;
public int Age
{
get { return age; }
set
{
age = value;
if(OnPropertyChanged!=null)
{
OnPropertyChanged();
}
}
}
}
學(xué)過(guò)MVVM模式的朋友對(duì)以上代碼是否有似曾相識(shí)的感覺(jué),用csc.exe編譯后再用ILDASM反編譯成文本文件:
.class public auto ansi beforefieldinit Test extends[mscorlib]System.Object
{
.method public hidebysig staticvoid Main(string[] args) cil managed
{
.entrypoint
//
.maxstack 3
.locals init (class EventTestV_0)
IL_0000: nop
IL_0001: newobj instance voidEventTest::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldnull
IL_0009: ldftn void Test::show()
IL_000f: newobj instance void EventTest/PropertyChangedHandler::.ctor(object,native int)
IL_0014: callvirt instance void EventTest::add_OnPropertyChanged(classEventTest/PropertyChangedHandler)
IL_0019: nop
IL_001a: ldloc.0
IL_001b: ldc.i4.2
IL_001c: callvirt instance void EventTest::set_Age(int32)
IL_0021: nop
IL_0022: ret
} // end of method Test::Main
.method public hidebysig staticvoid show() cil managed
{
//
.maxstack 8
IL_0000: nop
IL_0001: ldstr "event trigged"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method Test::show
.method public hidebysigspecialname rtspecialname instancevoid .ctor() cil managed
{
//
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method Test::.ctor
} // end of class Test
.class public auto ansi beforefieldinitEventTest extends [mscorlib]System.Object
{
.class auto ansi sealed nestedpublic PropertyChangedHandler extends[mscorlib]System.MulticastDelegate
{
.method public hidebysigspecialname rtspecialname instancevoid .ctor(object 'object', native int 'method') runtime managed
{
} // end of methodPropertyChangedHandler::.ctor
.method public hidebysig newslotvirtual instance void Invoke() runtime managed
{
} // end of methodPropertyChangedHandler::Invoke
.method public hidebysig newslotvirtual instance class[mscorlib]System.IAsyncResult
BeginInvoke(class[mscorlib]System.AsyncCallback callback, object 'object') runtime managed
{
} // end of methodPropertyChangedHandler::BeginInvoke
.method public hidebysig newslotvirtual instance void EndInvoke(class [mscorlib]System.IAsyncResultresult) runtime managed
{
} // end of methodPropertyChangedHandler::EndInvoke
} // end of classPropertyChangedHandler
.field private classEventTest/PropertyChangedHandlerOnPropertyChanged
.field private int32 age
.method public hidebysigspecialname instance void add_OnPropertyChanged(classEventTest/PropertyChangedHandler 'value') cil managed
{
//
.maxstack 3
.locals init (classEventTest/PropertyChangedHandler V_0,
classEventTest/PropertyChangedHandler V_1,
classEventTest/PropertyChangedHandler V_2,
bool V_3)
IL_0000: ldarg.0
IL_0001: ldfld class EventTest/PropertyChangedHandler EventTest::OnPropertyChanged
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: stloc.1
IL_0009: ldloc.1
IL_000a: ldarg.1
IL_000b: call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class[mscorlib]System.Delegate,
class [mscorlib]System.Delegate)
IL_0010: castclass EventTest/PropertyChangedHandler
IL_0015: stloc.2
IL_0016: ldarg.0
IL_0017: ldflda class EventTest/PropertyChangedHandler EventTest::OnPropertyChanged
IL_001c: ldloc.2
IL_001d: ldloc.1
IL_001e: call !!0 [mscorlib]System.Threading.Interlocked::CompareExchange<classEventTest/PropertyChangedHandler>(!!0&, !!0, !!0)
IL_0023: stloc.0
IL_0024: ldloc.0
IL_0025: ldloc.1
IL_0026: ceq
IL_0028: ldc.i4.0
IL_0029: ceq
IL_002b: stloc.3
IL_002c: ldloc.3
IL_002d: brtrue.s IL_0007
IL_002f: ret
} // end of methodEventTest::add_OnPropertyChanged
.method public hidebysigspecialname instance void
remove_OnPropertyChanged(classEventTest/PropertyChangedHandler 'value') cil managed
{
//
.maxstack 3
.locals init (classEventTest/PropertyChangedHandler V_0,
classEventTest/PropertyChangedHandler V_1,
classEventTest/PropertyChangedHandler V_2,
bool V_3)
IL_0000: ldarg.0
IL_0001: ldfld class EventTest/PropertyChangedHandler EventTest::OnPropertyChanged
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: stloc.1
IL_0009: ldloc.1
IL_000a: ldarg.1
IL_000b: call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Remove(class [mscorlib]System.Delegate,
class [mscorlib]System.Delegate)
IL_0010: castclass EventTest/PropertyChangedHandler
IL_0015: stloc.2
IL_0016: ldarg.0
IL_0017: ldflda class EventTest/PropertyChangedHandler EventTest::OnPropertyChanged
IL_001c: ldloc.2
IL_001d: ldloc.1
IL_001e: call !!0 [mscorlib]System.Threading.Interlocked::CompareExchange<classEventTest/PropertyChangedHandler>(!!0, !!0, !!0)
IL_0023: stloc.0
IL_0024: ldloc.0
IL_0025: ldloc.1
IL_0026: ceq
IL_0028: ldc.i4.0
IL_0029: ceq
IL_002b: stloc.3
IL_002c: ldloc.3
IL_002d: brtrue.s IL_0007
IL_002f: ret
} // end of methodEventTest::remove_OnPropertyChanged
.method public hidebysigspecialname instance int32 get_Age() cil managed
{
//
.maxstack 1
.locals init (int32 V_0)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldfld int32 EventTest::age
IL_0007: stloc.0
IL_0008: br.s IL_000a
IL_000a: ldloc.0
IL_000b: ret
} // end of methodEventTest::get_Age
.method public hidebysigspecialname instance void set_Age(int32'value') cil managed
{
//
.maxstack 2
.locals init (bool V_0)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.1
IL_0003: stfld int32 EventTest::age
IL_0008: ldarg.0
IL_0009: ldfld class EventTest/PropertyChangedHandlerEventTest::OnPropertyChanged
IL_000e: ldnull
IL_000f: ceq
IL_0011: stloc.0
IL_0012: ldloc.0
IL_0013: brtrue.s IL_0023
IL_0015: nop
IL_0016: ldarg.0
IL_0017: ldfld class EventTest/PropertyChangedHandler EventTest::OnPropertyChanged
IL_001c: callvirt instance void EventTest/PropertyChangedHandler::Invoke()
IL_0021: nop
IL_0022: nop
IL_0023: ret
} // end of methodEventTest::set_Age
.method public hidebysigspecialname rtspecialname instance void .ctor() cil managed
{
//
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of methodEventTest::.ctor
.eventEventTest/PropertyChangedHandler OnPropertyChanged
{
.addon instancevoid EventTest::add_OnPropertyChanged(class EventTest/PropertyChangedHandler)
.removeoninstance void EventTest::remove_OnPropertyChanged(classEventTest/PropertyChangedHandler)
} // end of eventEventTest::OnPropertyChanged
.property instance int32 Age()
{
.get instance int32EventTest::get_Age()
.set instance voidEventTest::set_Age(int32)
} // end of propertyEventTest::Age
} // end of class EventTest
用event聲明事件后編譯器在編譯時(shí)給類中加了二個(gè)方法:
add_OnPropertyChanged(class EventTest/PropertyChangedHandler 'value')、
remove _OnPropertyChanged(class EventTest/PropertyChangedHandler 'value')。
在這二個(gè)方法中有二個(gè)調(diào)用:
System.Delegate::Combine(class [mscorlib]System.Delegate, class[mscorlib]System.Delegate)、
System.Delegate::Remove(class[mscorlib]System.Delegate, class[mscorlib]System.Delegate),
查一下MSDN這二個(gè)調(diào)用是干什么的:
Combine方法將兩個(gè)委托的調(diào)用列表連接在一起,Remove方法從一個(gè)委托的調(diào)用列表中移除另一個(gè)委托的最后一個(gè)調(diào)用列表。
委托里有個(gè)調(diào)用列表!
挖到這里,學(xué)過(guò)觀察者模式的朋友是否有似曾相識(shí)的感覺(jué):觀察者模式中被觀察者也有一個(gè)訂閱者列表,有Add和Remove方法。事件模式不就是觀察者模式嗎?,不過(guò)在C#中用delegate來(lái)實(shí)現(xiàn)觀察者模式中的更新狀態(tài)的接口和訂閱者列表,用event關(guān)鍵字實(shí)現(xiàn)的訂閱者的添加和刪除。
理解了事件模式和觀察者模式的關(guān)系,對(duì)MVVM模式中的Notification類也就不難理解了。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注