C# 이벤트는 무대 뒤에서 어떻게 작동합니까?
문제
C#, .NET 3.5를 사용하고 있습니다. 이벤트를 활용하는 방법, 수업에서 이벤트를 선언하는 방법, 다른 곳에서 연결하는 방법 등을 이해합니다.
public class MyList
{
private List<string> m_Strings = new List<string>();
public EventHandler<EventArgs> ElementAddedEvent;
public void Add(string value)
{
m_Strings.Add(value);
if (ElementAddedEvent != null)
ElementAddedEvent(value, EventArgs.Empty);
}
}
[TestClass]
public class TestMyList
{
private bool m_Fired = false;
[TestMethod]
public void TestEvents()
{
MyList tmp = new MyList();
tmp.ElementAddedEvent += new EventHandler<EventArgs>(Fired);
tmp.Add("test");
Assert.IsTrue(m_Fired);
}
private void Fired(object sender, EventArgs args)
{
m_Fired = true;
}
}
그러나 내가하는 일 ~ 아니다 이해, 이벤트 핸들러를 선언 할 때입니다
public EventHandler<EventArgs> ElementAddedEvent;
초기화되지 않았습니다. 따라서 ElementAddedEvent는 정확히 무엇입니까? 그것은 무엇을 가리키나요? 이벤트 핸들러가 초기화되지 않기 때문에 다음은 작동하지 않습니다.
[TestClass]
public class TestMyList
{
private bool m_Fired = false;
[TestMethod]
public void TestEvents()
{
EventHandler<EventArgs> somethingHappend;
somethingHappend += new EventHandler<EventArgs>(Fired);
somethingHappend(this, EventArgs.Empty);
Assert.IsTrue(m_Fired);
}
private void Fired(object sender, EventArgs args)
{
m_Fired = true;
}
}
EventHandler.createdElegate (...)가 있음을 알 수 있지만 모든 메소드 서명은 이것이 일반적인 ElementAddedEvent += New EventHandler (MyMethod)를 통해 이미 기존 이벤트 핸들러에 대의원을 첨부하는 데만 사용된다고 제안합니다.
확실하지 않습니다 무엇 나는 도움이 될 것입니다 ... 그러나 궁극적으로 나는 LINQ의 추상적 인 부모 데이터 콘텍스트를 생각해 내고 싶습니다. 유형에 따라 다릅니다. 이 같은:
public class BaseDataContext : DataContext
{
private static Dictionary<Type, Dictionary<ChangeAction, EventHandler>> m_ObservedTypes = new Dictionary<Type, Dictionary<ChangeAction, EventHandler>>();
public static void Observe(Type type)
{
if (m_ObservedTypes.ContainsKey(type) == false)
{
m_ObservedTypes.Add(type, new Dictionary<ChangeAction, EventHandler>());
EventHandler eventHandler = EventHandler.CreateDelegate(typeof(EventHandler), null, null) as EventHandler;
m_ObservedTypes[type].Add(ChangeAction.Insert, eventHandler);
eventHandler = EventHandler.CreateDelegate(typeof(EventHandler), null, null) as EventHandler;
m_ObservedTypes[type].Add(ChangeAction.Update, eventHandler);
eventHandler = EventHandler.CreateDelegate(typeof(EventHandler), null, null) as EventHandler;
m_ObservedTypes[type].Add(ChangeAction.Delete, eventHandler);
}
}
public static Dictionary<Type, Dictionary<ChangeAction, EventHandler>> Events
{
get { return m_ObservedTypes; }
}
}
public class MyClass
{
public MyClass()
{
BaseDataContext.Events[typeof(User)][ChangeAction.Update] += new EventHandler(OnUserUpdate);
}
public void OnUserUpdated(object sender, EventArgs args)
{
// do something
}
}
이것에 대해 생각하면 나는 이벤트와 함께 HOD에서 무슨 일이 일어나고 있는지 이해하지 못한다는 것을 깨달았습니다. 그리고 나는 이해하고 싶습니다 :)
해결책
나는 이것을 상당한 양의 세부적으로 썼다. 기사,하지만 여기 요약이 있습니다. 대표 그들 자신:
- 이벤트는 속성이 실제로 "get"메소드이고 "세트"메소드 인 것과 같은 방식으로 "추가"메소드와 "제거"메소드입니다. (실제로 CLI는 "Raise/Fire"방법도 허용하지만 C#은 이것을 생성하지 않습니다.) 메타 데이터는 메소드에 대한 참조로 이벤트를 설명합니다.
- 당신이 선언 할 때 a 현장과 같은 이벤트 (ElementAddedEvent와 마찬가지로) 컴파일러는 메소드를 생성합니다. 그리고 개인 분야 (대의원과 같은 유형). 수업 내에서 ElementAddedEvent를 언급 할 때 필드를 언급합니다. 수업 밖에서, 당신은 현장을 언급하고 있습니다.
- 누구나 추가 메소드를 호출하는 이벤트 ( += 연산자 포함)를 구독 할 때. 제거를 취소 할 때 ( -= 연산자와 함께) 제거를 호출합니다.
필드와 같은 이벤트의 경우 약간의 동기화가 있지만 추가/제거는 대의원을 호출합니다.결합하다/제거하다 자동 생성 된 필드의 값을 변경합니다. 이 두 가지 작업은 후원장에 할당됩니다. 대표는 불변이라는 것을 기억하십시오. 다시 말해,자가 생성 코드는 다음과 매우 흡사합니다.
// Backing field // The underscores just make it simpler to see what's going on here. // In the rest of your source code for this class, if you refer to // ElementAddedEvent, you're really referring to this field. private EventHandler<EventArgs> __ElementAddedEvent; // Actual event public EventHandler<EventArgs> ElementAddedEvent { add { lock(this) { // Equivalent to __ElementAddedEvent += value; __ElementAddedEvent = Delegate.Combine(__ElementAddedEvent, value); } } remove { lock(this) { // Equivalent to __ElementAddedEvent -= value; __ElementAddedEvent = Delegate.Remove(__ElementAddedEvent, value); } } }
귀하의 경우 생성 된 필드의 초기 값은
null
- 그리고 그것은 항상 될 것입니다null
모든 가입자가 제거 된 경우 다시는 Delegate.remove의 동작입니다."No-OP"핸들러가 이벤트를 구독하여 무효 점검을 피하기 위해 다음을 수행 할 수 있습니다.
public EventHandler<EventArgs> ElementAddedEvent = delegate {};
그만큼
delegate {}
매개 변수를 신경 쓰지 않고 아무것도하지 않는 익명의 방법입니다.
여전히 불분명 한 것이 있다면 물어 보시면 도와 드리겠습니다!
다른 팁
후드 아래에서, 이벤트는 특별한 전화 규칙이있는 대의원 일뿐입니다. (예를 들어, 이벤트를 제기하기 전에 무효 점을 확인할 필요가 없습니다.)
pseudocode에서 event.invoke ()는 다음과 같이 분해됩니다.
이벤트에 청취자 가이 스레드에서 각 청취자를 동기식으로 호출하는 경우 임의 순서로.
이벤트는 멀티 캐스트이므로 컬렉션에 개최 된 리스너 이상이 0 이상이됩니다. CLR은 그들을 통과하여 각각 임의의 순서로 호출합니다.
기억해야 할 큰 경고 중 하나는 이벤트 핸들러가 이벤트가 제기되는 것과 동일한 스레드에서 실행된다는 것입니다. 새로운 스레드를 산란하는 것으로 생각하는 것은 일반적인 정신적 오류입니다. 그들은하지 않습니다.