나는 내가 제안하는 것이 .NET 지침을 따르지 않는다는 것을 완전히 알고 있으며, 따라서 이러한 이유만으로는 아마도 좋지 않은 생각 일 것입니다. 그러나 두 가지 가능한 관점에서 이것을 고려하고 싶습니다.
(1) 100 % 내부 용으로 개발 작업에 사용하는 것을 고려해야합니다.
(2) 이것은 프레임 워크 디자이너가 변경 또는 업데이트를 고려할 수있는 개념입니까?
현재 .NET 디자인 패턴 인 '객체'로 입력하는 대신 강력한 유형의 '보낸 사람'을 활용하는 이벤트 서명을 사용할 생각입니다. 즉, 다음과 같은 표준 이벤트 서명을 사용하는 대신 :
class Publisher
{
public event EventHandler<PublisherEventArgs> SomeEvent;
}
다음과 같이 강력한 형식의 '보낸 사람'매개 변수를 사용하는 이벤트 서명 사용을 고려하고 있습니다.
먼저 "StrongTypedEventHandler"를 정의합니다.
[SerializableAttribute]
public delegate void StrongTypedEventHandler<TSender, TEventArgs>(
TSender sender,
TEventArgs e
)
where TEventArgs : EventArgs;
이것은 Action <TSender, TEventArgs>와 크게 다르지 않지만를 사용 StrongTypedEventHandler
하여 TEventArgs가 System.EventArgs
.
다음으로, 예를 들어 다음과 같이 게시 클래스에서 StrongTypedEventHandler를 사용할 수 있습니다.
class Publisher
{
public event StrongTypedEventHandler<Publisher, PublisherEventArgs> SomeEvent;
protected void OnSomeEvent()
{
if (SomeEvent != null)
{
SomeEvent(this, new PublisherEventArgs(...));
}
}
}
위의 배열을 통해 구독자는 캐스팅이 필요하지 않은 강력한 유형의 이벤트 처리기를 사용할 수 있습니다.
class Subscriber
{
void SomeEventHandler(Publisher sender, PublisherEventArgs e)
{
if (sender.Name == "John Smith")
{
// ...
}
}
}
나는 이것이 표준 .NET 이벤트 처리 패턴으로 깨진다는 것을 완전히 알고 있습니다. 그러나 반 변성은 구독자가 원하는 경우 기존 이벤트 처리 서명을 사용할 수 있도록합니다.
class Subscriber
{
void SomeEventHandler(object sender, PublisherEventArgs e)
{
if (((Publisher)sender).Name == "John Smith")
{
// ...
}
}
}
즉, 이벤트 처리기가 서로 다른 (또는 알 수없는) 개체 유형의 이벤트를 구독해야하는 경우 처리기는 잠재적 인 발신자 개체의 전체 범위를 처리하기 위해 'sender'매개 변수를 'object'로 입력 할 수 있습니다.
관습을 깨뜨리는 것 외에 (저를 가볍게 받아들이지 않는 것입니다.) 저는 이것에 대한 어떤 단점도 생각할 수 없습니다.
여기에 몇 가지 CLS 규정 준수 문제가있을 수 있습니다. 이것은 Visual Basic .NET 2008에서 100 % 잘 실행되지만 (필자가 테스트 한) 이전 버전의 Visual Basic .NET에서 2005 년까지의 이전 버전에는 대리자 공분산 및 반공 변성이 없다고 생각합니다. [편집 : 나는 이것을 테스트 한 이후로 확인되었습니다 : VB.NET 2005 이하에서는 이것을 처리 할 수 없지만 VB.NET 2008은 100 % 괜찮습니다. 아래의 "편집 # 2"를 참조하십시오.] 이 문제가있는 다른 .NET 언어가있을 수 있습니다. 확실하지 않습니다.
그러나 나는 C # 또는 Visual Basic .NET 이외의 다른 언어로 개발하는 것을 보지 않으며 .NET Framework 3.0 이상을 위해 C # 및 VB.NET으로 제한하는 것을 신경 쓰지 않습니다. (솔직히이 시점에서 2.0으로 돌아가는 것은 상상할 수 없습니다.)
다른 사람이 이것에 대한 문제를 생각할 수 있습니까? 아니면 이것은 단순히 관습을 너무 많이 깨뜨려 사람들의 배를 돌리게하는 것일까 요?
내가 찾은 관련 링크는 다음과 같습니다.
(2) C # 단순 이벤트 발생- "보낸 사람"대 사용자 지정 EventArgs 사용 [StackOverflow 2009]
(3) .net의 이벤트 시그니처 패턴 [StackOverflow 2008]
나는 이것에 대한 모든 사람의 의견에 관심이 있습니다 ...
미리 감사드립니다.
마이크
편집 # 1 : 이것은 Tommy Carlier의 게시물 에 대한 응답입니다 .
다음은 강력한 형식의 이벤트 처리기와 '객체 전송자'매개 변수를 사용하는 현재 표준 이벤트 처리기가이 접근 방식과 공존 할 수 있음을 보여주는 전체 작동 예제입니다. 코드를 복사하여 붙여넣고 실행할 수 있습니다.
namespace csScrap.GenericEventHandling
{
class PublisherEventArgs : EventArgs
{
// ...
}
[SerializableAttribute]
public delegate void StrongTypedEventHandler<TSender, TEventArgs>(
TSender sender,
TEventArgs e
)
where TEventArgs : EventArgs;
class Publisher
{
public event StrongTypedEventHandler<Publisher, PublisherEventArgs> SomeEvent;
public void OnSomeEvent()
{
if (SomeEvent != null)
{
SomeEvent(this, new PublisherEventArgs());
}
}
}
class StrongTypedSubscriber
{
public void SomeEventHandler(Publisher sender, PublisherEventArgs e)
{
MessageBox.Show("StrongTypedSubscriber.SomeEventHandler called.");
}
}
class TraditionalSubscriber
{
public void SomeEventHandler(object sender, PublisherEventArgs e)
{
MessageBox.Show("TraditionalSubscriber.SomeEventHandler called.");
}
}
class Tester
{
public static void Main()
{
Publisher publisher = new Publisher();
StrongTypedSubscriber strongTypedSubscriber = new StrongTypedSubscriber();
TraditionalSubscriber traditionalSubscriber = new TraditionalSubscriber();
publisher.SomeEvent += strongTypedSubscriber.SomeEventHandler;
publisher.SomeEvent += traditionalSubscriber.SomeEventHandler;
publisher.OnSomeEvent();
}
}
}
편집 # 2 : 이것은 공분산 및 반공 변성에 관한 Andrew Hare의 진술 과 여기에 적용되는 방법 에 대한 응답 입니다. C # 언어의 델리게이트는 오랫동안 공분산과 반공 변성을 가지고있어 "내재적"이라고 느껴지지만 그렇지 않습니다. CLR에서 활성화 된 것일 수도 있지만, Visual Basic .NET은 .NET Framework 3.0 (VB.NET 2008)이 출시 될 때까지 대리자에 대한 공분산 및 반공 변성 기능을 얻지 못했습니다. 결과적으로 Visual Basic.NET for .NET 2.0 이하에서는이 접근 방식을 사용할 수 없습니다.
예를 들어, 위의 예는 다음과 같이 VB.NET으로 변환 될 수 있습니다.
Namespace GenericEventHandling
Class PublisherEventArgs
Inherits EventArgs
' ...
' ...
End Class
<SerializableAttribute()> _
Public Delegate Sub StrongTypedEventHandler(Of TSender, TEventArgs As EventArgs) _
(ByVal sender As TSender, ByVal e As TEventArgs)
Class Publisher
Public Event SomeEvent As StrongTypedEventHandler(Of Publisher, PublisherEventArgs)
Public Sub OnSomeEvent()
RaiseEvent SomeEvent(Me, New PublisherEventArgs)
End Sub
End Class
Class StrongTypedSubscriber
Public Sub SomeEventHandler(ByVal sender As Publisher, ByVal e As PublisherEventArgs)
MessageBox.Show("StrongTypedSubscriber.SomeEventHandler called.")
End Sub
End Class
Class TraditionalSubscriber
Public Sub SomeEventHandler(ByVal sender As Object, ByVal e As PublisherEventArgs)
MessageBox.Show("TraditionalSubscriber.SomeEventHandler called.")
End Sub
End Class
Class Tester
Public Shared Sub Main()
Dim publisher As Publisher = New Publisher
Dim strongTypedSubscriber As StrongTypedSubscriber = New StrongTypedSubscriber
Dim traditionalSubscriber As TraditionalSubscriber = New TraditionalSubscriber
AddHandler publisher.SomeEvent, AddressOf strongTypedSubscriber.SomeEventHandler
AddHandler publisher.SomeEvent, AddressOf traditionalSubscriber.SomeEventHandler
publisher.OnSomeEvent()
End Sub
End Class
End Namespace
VB.NET 2008은 100 % 잘 실행할 수 있습니다. 하지만 지금은 VB.NET 2005에서 테스트를 해봤습니다. 확실히하기 위해 다음과 같이 컴파일되지 않습니다.
'Public Sub SomeEventHandler (sender As Object, e As vbGenericEventHandling.GenericEventHandling.PublisherEventArgs)'메서드에 'Delegate Sub StrongTypedEventHandler (Of TSender, TEventArgs As System.EventArgs) (sender As Publisher, e As PublisherEventArgs)'대리자와 동일한 서명이 없습니다. '
기본적으로 VB.NET 버전 2005 이하에서는 대리자가 변하지 않습니다. 사실 저는이 아이디어를 몇 년 전에 생각했지만 VB.NET이이 문제를 처리 할 수 없었습니다 ...하지만 이제는 C #으로 확고하게 이동했으며 이제 VB.NET에서 처리 할 수 있습니다. 이 게시물.
편집 : 업데이트 # 3
좋아, 나는 이것을 꽤 성공적으로 사용하고 있습니다. 정말 멋진 시스템입니다. 내 "StrongTypedEventHandler"의 이름을 "GenericEventHandler"로 지정하고 다음과 같이 정의했습니다.
[SerializableAttribute]
public delegate void GenericEventHandler<TSender, TEventArgs>(
TSender sender,
TEventArgs e
)
where TEventArgs : EventArgs;
이 이름 변경 외에 위에서 설명한대로 정확하게 구현했습니다.
다음과 같은 FxCop 규칙 CA1009를 넘어갑니다.
"관습 적으로 .NET 이벤트에는 이벤트 발신자와 이벤트 데이터를 지정하는 두 개의 매개 변수가 있습니다. 이벤트 핸들러 서명은 void MyEventHandler (object sender, EventArgs e)) 형식을 따라야합니다. 'sender'매개 변수는 항상 System.Object 유형입니다. 보다 구체적인 형식을 사용할 수있는 경우에도 'e'매개 변수는 항상 System.EventArgs 형식입니다. 이벤트 데이터를 제공하지 않는 이벤트는 System.EventHandler 대리자 형식을 사용해야합니다. 이벤트 처리기는 보낼 수 있도록 void를 반환합니다. 각 이벤트를 여러 대상 메서드에 추가합니다. 대상에서 반환 한 모든 값은 첫 번째 호출 후 손실됩니다. "
물론 우리는이 모든 것을 알고 있으며 어쨌든 규칙을 위반하고 있습니다. (모든 이벤트 핸들러는 어떤 경우 에든 선호하는 경우 서명에 표준 '객체 발신자'를 사용할 수 있습니다. 이것은 비파괴적인 변경입니다.)
따라서 a의 사용은 SuppressMessageAttribute
트릭을 수행합니다.
[SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly",
Justification = "Using strong-typed GenericEventHandler<TSender, TEventArgs> event handler pattern.")]
이 접근 방식이 언젠가는 표준이되기를 바랍니다. 정말 잘 작동합니다.
모든 의견 주셔서 감사합니다. 정말 감사합니다 ...
마이크
oh hi this my hom work solve it plz :code dump:
질문 중 하나가 아니라에서 배운 질문 입니다 .
EventHandler<,>
은 GenericEventHandler<,>
. EventHandler<>
BCL 에는 이미 EventHandler라는 일반이 있습니다 . 그래서 EventHandler는 더 일반적인 이름이고 델리게이트는 타입 오버로드를 지원합니다