답변:
질문에 답하려면 :
나도 내부 메커니즘 event
과 관련 작업 에 대해 궁금 했습니다. 그래서 저는 간단한 프로그램을 작성하고 ildasm
그 구현을 찌르는 데 사용 했습니다.
짧은 대답은
Delegate.Combine()
Delegate.Remove()
여기 내가 한 일이 있습니다. 내가 사용한 프로그램 :
public class Foo
{
// cool, it can return a value! which value it returns if there're multiple
// subscribers? answer (by trying): the last subscriber.
public event Func<int, string> OnCall;
private int val = 1;
public void Do()
{
if (OnCall != null)
{
var res = OnCall(val++);
Console.WriteLine($"publisher got back a {res}");
}
}
}
public class Program
{
static void Main(string[] args)
{
var foo = new Foo();
foo.OnCall += i =>
{
Console.WriteLine($"sub2: I've got a {i}");
return "sub2";
};
foo.OnCall += i =>
{
Console.WriteLine($"sub1: I've got a {i}");
return "sub1";
};
foo.Do();
foo.Do();
}
}
다음은 Foo의 구현입니다.
있음을 유의 필드 OnCall
와 이벤트 OnCall
. 필드 OnCall
는 분명히 뒷받침 속성입니다. 그리고 그것은 단지 Func<int, string>
.
이제 흥미로운 부분은 다음과 같습니다.
add_OnCall(Func<int, string>)
remove_OnCall(Func<int, string>)
OnCall
호출 되는지Do()
다음 add_OnCall
은 CIL 의 축약 된 구현입니다. 흥미로운 부분은 Delegate.Combine
두 대리자를 연결 하는 데 사용 된다는 것입니다.
.method public hidebysig specialname instance void
add_OnCall(class [mscorlib]System.Func`2<int32,string> 'value') cil managed
{
// ...
.locals init (class [mscorlib]System.Func`2<int32,string> V_0,
class [mscorlib]System.Func`2<int32,string> V_1,
class [mscorlib]System.Func`2<int32,string> V_2)
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Func`2<int32,string> ConsoleApp1.Foo::OnCall
// ...
IL_000b: call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate,
class [mscorlib]System.Delegate)
// ...
} // end of method Foo::add_OnCall
마찬가지로 Delegate.Remove
사용된다 remove_OnCall
.
호출하기 OnCall
에 Do()
, 단순히 인수를로드 한 후 최종 연결된 대리자를 호출합니다 :
IL_0026: callvirt instance !1 class [mscorlib]System.Func`2<int32,string>::Invoke(!0)
마지막으로 Main
놀랍게도에서 OnCall
이벤트 구독 add_OnCall
은 Foo
인스턴스에서 메서드를 호출하여 수행됩니다 .
이것은 일반적인 대답이며 기본 동작을 반영합니다.
하지만 이벤트를 제공하는 모든 클래스는 이벤트를 비동기 적으로 구현하도록 선택할 수 있습니다. IDesign은이EventsHelper
를 단순화 하는 클래스를 제공합니다 .
[참고] 이 링크는 EventsHelper 클래스를 다운로드하기 위해 이메일 주소를 제공해야합니다. (저는 어떤 식 으로든 제휴하지 않습니다)
이벤트는 델리게이트의 배열 일뿐입니다. 대리자 호출이 동기식이면 이벤트도 동기식입니다.
일반적으로 이벤트는 동기식입니다. 그러나 다음과 같은 경우 스레드 System.Timers.Timer.Elapsed
에서 이벤트가 발생하는 것과 같은 몇 가지 예외가 있습니다.ThreadPool
SyncronisingObject
null 인 가 있습니다.
문서 : http://msdn.microsoft.com/en-us/library/system.timers.timer.elapsed.aspx
C #의 이벤트는 두 번째 스레드를 수동으로 시작하지 않는 한 동 기적으로 (두 경우 모두) 실행됩니다.