+ = new EventHandler (Method) vs + = Method
중복 가능성 :
C # : '+ = anEvent'와 '+ = new EventHandler (anEvent)'의 차이
이벤트를 구독하는 기본 방법은 두 가지입니다.
SomeEvent += new EventHandler<ArgType> (MyHandlerMethod);
SomeEvent += MyHandlerMethod;
차이점은 무엇이며 언제 다른 것을 선택해야합니까?
편집 : 동일하다면 왜 VS가 긴 버전으로 기본 설정되어 코드가 복잡합니까? 그것은 나에게 전혀 의미가 없습니다.
내 원래의 대답을 통해 약간의 분쟁이있을 것 같았다 때문에, 나는 생성 된 코드에서 찾고 포함, 몇 가지 검사를하기로 결정 하고 성능을 모니터링.
우선, 여기에 우리의 테스트 베드, 델리게이트가있는 클래스와 그것을 소비 할 다른 클래스가 있습니다.
class EventProducer
{
public void Raise()
{
var handler = EventRaised;
if (handler != null)
handler(this, EventArgs.Empty);
}
public event EventHandler EventRaised;
}
class Counter
{
long count = 0;
EventProducer producer = new EventProducer();
public void Count()
{
producer.EventRaised += CountEvent;
producer.Raise();
producer.EventRaised -= CountEvent;
}
public void CountWithNew()
{
producer.EventRaised += new EventHandler(CountEvent);
producer.Raise();
producer.EventRaised -= new EventHandler(CountEvent);
}
private void CountEvent(object sender, EventArgs e)
{
count++;
}
}
가장 먼저 할 일은 생성 된 IL을 보는 것입니다.
.method public hidebysig instance void Count() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: ldfld class DelegateTest.Program/EventProducer DelegateTest.Program/Counter::producer
L_0006: ldarg.0
L_0007: ldftn instance void DelegateTest.Program/Counter::CountEvent(object, class [mscorlib]System.EventArgs)
L_000d: newobj instance void [mscorlib]System.EventHandler::.ctor(object, native int)
L_0012: callvirt instance void DelegateTest.Program/EventProducer::add_EventRaised(class [mscorlib]System.EventHandler)
L_0017: ldarg.0
L_0018: ldfld class DelegateTest.Program/EventProducer DelegateTest.Program/Counter::producer
L_001d: callvirt instance void DelegateTest.Program/EventProducer::Raise()
L_0022: ldarg.0
L_0023: ldfld class DelegateTest.Program/EventProducer DelegateTest.Program/Counter::producer
L_0028: ldarg.0
L_0029: ldftn instance void DelegateTest.Program/Counter::CountEvent(object, class [mscorlib]System.EventArgs)
L_002f: newobj instance void [mscorlib]System.EventHandler::.ctor(object, native int)
L_0034: callvirt instance void DelegateTest.Program/EventProducer::remove_EventRaised(class [mscorlib]System.EventHandler)
L_0039: ret
}
.method public hidebysig instance void CountWithNew() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: ldfld class DelegateTest.Program/EventProducer DelegateTest.Program/Counter::producer
L_0006: ldarg.0
L_0007: ldftn instance void DelegateTest.Program/Counter::CountEvent(object, class [mscorlib]System.EventArgs)
L_000d: newobj instance void [mscorlib]System.EventHandler::.ctor(object, native int)
L_0012: callvirt instance void DelegateTest.Program/EventProducer::add_EventRaised(class [mscorlib]System.EventHandler)
L_0017: ldarg.0
L_0018: ldfld class DelegateTest.Program/EventProducer DelegateTest.Program/Counter::producer
L_001d: callvirt instance void DelegateTest.Program/EventProducer::Raise()
L_0022: ldarg.0
L_0023: ldfld class DelegateTest.Program/EventProducer DelegateTest.Program/Counter::producer
L_0028: ldarg.0
L_0029: ldftn instance void DelegateTest.Program/Counter::CountEvent(object, class [mscorlib]System.EventArgs)
L_002f: newobj instance void [mscorlib]System.EventHandler::.ctor(object, native int)
L_0034: callvirt instance void DelegateTest.Program/EventProducer::remove_EventRaised(class [mscorlib]System.EventHandler)
L_0039: ret
}
So it turns out that, yes, these do generate identical IL. I was wrong originally. But that's not the whole story. It may be that I'm going off-topic here but I think that it's important to include this when talking about events and delegates:
Creating and comparing different delegates is not cheap.
When I wrote this, I was thinking that the first syntax was able to cast the method group as a delegate, but it turns out that it's just a conversion. But it's completely different when you actually save the delegate. If we add this to the consumer:
class Counter
{
EventHandler savedEvent;
public Counter()
{
savedEvent = CountEvent;
}
public void CountSaved()
{
producer.EventRaised += savedEvent;
producer.Raise();
producer.EventRaised -= savedEvent;
}
}
You can see that this has very different characteristics, performance-wise, from the other two:
static void Main(string[] args)
{
const int TestIterations = 10000000;
TimeSpan countTime = TestCounter(c => c.Count());
Console.WriteLine("Count: {0}", countTime);
TimeSpan countWithNewTime = TestCounter(c => c.CountWithNew());
Console.WriteLine("CountWithNew: {0}", countWithNewTime);
TimeSpan countSavedTime = TestCounter(c => c.CountSaved());
Console.WriteLine("CountSaved: {0}", countSavedTime);
Console.ReadLine();
}
static TimeSpan TestCounter(Action<Counter> action, int iterations)
{
var counter = new Counter();
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < TestIterations; i++)
action(counter);
sw.Stop();
return sw.Elapsed;
}
The results consistently come back as something similar to:
Count: 00:00:02.4742007
CountWithNew: 00:00:02.4272702
CountSaved: 00:00:01.9810367
That's nearly a 20% difference when using a saved delegate vs. creating a new one.
Now obviously not every program is going to be adding and removing this many delegates in such a small amount of time, but if you're writing library classes - classes that might be used in ways you cannot predict - then you really want to keep this difference in mind if you ever need to add and remove events (and I've written a lot of code that does this, personally).
So the conclusion of this is, writing SomeEvent += new EventHandler(NamedMethod)
compiles to the same thing as just SomeEvent += NamedMethod
. But if you plan to remove that event handler later, you really should save the delegate. Even though the Delegate
class has some special-case code that allows you to remove a referentially-different delegate from the one you added, it has to do a non-trivial amount of work to pull this off.
If you're not going to save the delegate, then it makes no difference - the compiler ends up creating a new delegate anyway.
There is no difference from a programming perspective, they are each others equivalent. The compiler will pretty much do what you have done on the first line with the second line behind the scenes. So I would always opt for the second approach (less code).
Re: Your Edit
Probably because they feel its better to show developers the proper way of doing things rather than shortcuts. Your guess is as good as mine :)
the second form is syntactic sugar introduced in later versions of c#. the first line will work in every version though
There's no difference. Prior to .NET 2.0, every variable assignments must be of exact type, compilers then didn't infer much. So as to make a work-around, VS 2003 emit new EventHandler
around the function name. That's just my guess. Because..
I tried something now in VS 2008, textBox1.KeyDown += (KeyEventHandler)textBox1_KeyDown
, that also work. It puzzles me why they choose new EventHandler(checkBox1_CheckStateChanged)
, rather than (EventHandler)checkBox1_CheckStateChanged
then. But...
as I don't have VS 2003 in my box anymore, I can't pin down if the casting approach could also work on VS 2003. But afaict, I tried removing new EventHandler
on function name when I used VS 2003 (.NET 1.1), deeming why the need to instantiate (new EventHandler
) a function, delegates are just function pointer under the hood, but it doesn't work.
It's only from .NET 2.0 onwards that C# compiler started to infer as much as possible.
This article http://blueonionsoftware.com/blog.aspx?p=aed2ae46-7548-4e5f-83c6-95e00c6f3649 supported my memory of new EventHandler
prior to .NET 2.0 compilers, it was a compulsary
[EDIT]
The following article goes in depth about subscribing/unsubcribing events, purporting there's a difference between button1.Click += new EventHandler(button1_Click);
and button1.Click += button1_Click;
, but sadly I can't see any difference in IL level though :-(
http://blogs.msdn.com/abhinaba/archive/2005/08/26/456437.aspx
There is no difference, the first one just is more specific in its definition.
참고URL : https://stackoverflow.com/questions/2749868/new-eventhandlermethod-vs-method
'Program Tip' 카테고리의 다른 글
Haskell의 Data.Typeable은 무엇입니까? (0) | 2020.10.27 |
---|---|
Jenkins 편안한 API 참조는 어디에서 찾을 수 있습니까? (0) | 2020.10.27 |
대용량 Java 힙 덤프 분석 도구 (0) | 2020.10.27 |
루비의 문자열 연결과 보간 (0) | 2020.10.27 |
아티팩트를 다른 스테이지로 어떻게 전달할 수 있습니까? (0) | 2020.10.27 |