On Thu, 15 Apr 2004 11:37:01 -0500, Daniel O'Connell [C# MVP]
-What have you found out?
Not much, all I can see is a vauge pattern and thats it. I havn't had
the time to do any indepth research however. I'll try to reply here
if I
find anything else.
-I have moved those delegates into the namespace. But I left the
sender
as the type of that class instead of Object. Should I set it to
ject? -I don't see the point of setting it to object since it is
only
used by one class. Type casting is 50% slower for reference types,
while
for value types it is a lot slower (boxing/unboxing). I can't
recall
the
actual number that I have tested, 10 million or 100 million, in any
case 1
and many zeros. It took about a second to run, 1.5 seconds to run
with
casting to and from object, and almost 6 seconds when boxing/unboxing
(changed it from class to struct). I try to keep casting and boxing
to
a
minimum. Because of this, System.Collection is pretty useless to me.
Especially since I have to deal with a lot of structs. I hate that
generics weren't released with v1.0. It makes me write a lot of
useless code, and reinvent the wheel.
Frankly, that performance really isn't likely to be too important. Are
you
writing anything that needs to deal with 100million events in a
second?
That
seems awful high to me. Same with System.Collection, how many
100million
accesses\sec are you tryign to do?
Anyway, thats irrelevent. Using a specific type as the sender would be
ok,
IMHO, if the event doesn't have to be genericly usable. Its a
judgement
call, I think, one I wouldn't be opposed to. I would however still
recommend
EventArgs in most situations, if your sender doesn't matter than
omitting that may be ok.
On Sun, 11 Apr 2004 13:57:19 -0500, Daniel O'Connell [C# MVP]
I know that you can't have an event in the namespace. I made a
mistake
there.
The (object sender, EventArgs e) model is not consistent. There
are
events that don't have a sender, only a derivative of EventArgs in
windows
forms. If there are events without sender, why shouldn't there be
events
I don't know of many of these off hand, but I would say it was a bad
choice
not to include a sender, especialy in windows forms. Thinking about
it
now I
think the sender value is most common in winddows forms but I'm not
sure.
I'll do a bit more research tonight and see what I can find. Watch
This Space.
without EventArgs with just the sender? Why don't you recomment
having
Foobar.EventHandler (inside the class name) if only that class is
using
it, and having the sender as Foobar instead of object?
For code clarity, I always suggest not nesting any class that
doesn't
have
to be nested. I feel that nested classes are going to be harder to
find and
users not using a nice IDE may have a bit of trouble finding that
delegate.
I also think that a class being nested suggests that that class uses
some of
the internals of the containing class, whcih a delegate will never
do.
By the way, I know that public delegate void FoobarDelegate(object
sender, EventArgs e); is syntax sugar for:
public class FoobarDelegate : MulticastDelegate {...}
.class public auto sealed ansi FoobarDelegate
extends [mscorlib]System.MulticastDelegate
{
.method public hidebysig specialname rtspecialname instance
void
.ctor(object 'object', native int 'method') runtime managed
{
}
.method public virtual hidebysig instance void Invoke(object
sender,
class [mscorlib]System.EventArgs e) runtime managed
{
}
.method public virtual hidebysig newslot instance class
[mscorlib]System.IAsyncResult BeginInvoke(object sender, class
[mscorlib]System.EventArgs e, class [mscorlib]System.AsyncCallback
callback, object 'object') runtime managed
{
}
.method public virtual hidebysig newslot instance void
EndInvoke(class
[mscorlib]System.IAsyncResult result) runtime managed
{
}
}
This would be an inner class if you do Foobar.FoobarDelegate.
I've been playing with delegate declarations, and it is always
using
MulticastDelegate instead of Delegate, even when you don't add
events
and
the return value is something other than void.
That is an oddity of the framework. It seems that once upon a time
there
would be both Multicast and Singlecast delegates available. That was
apparently cut, but much of the infrastructure is still there.
The event part is a little hard to understand. I understand that
if
MulticastDelegate had +\- only, it wouldn't allow you to do
FoobarDelegate
f = (FoobarDelegate) foo;. It would have forced you to work with
only one
reference of FoobarDelegate.
You have this in a class, which seems to me that it is masking a
class as
a field:
.field private class DataStructuresTests.FoobarDelegate FoobarEvent
Then you have the stuff bellow in the class where the event was
declared:
.method public hidebysig specialname instance void
add_FoobarEvent(class DataStructuresTests.FoobarDelegate 'value')
cil
managed synchronized
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.0
IL_0002: ldfld class DataStructuresTests.FoobarDelegate
DataStructuresTests.Tester::FoobarEvent
IL_0007: ldarg.1
IL_0008: call class [mscorlib]System.Delegate
[mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate,
class
[mscorlib]System.Delegate)
IL_000d: castclass class DataStructuresTests.FoobarDelegate
IL_0012: stfld class DataStructuresTests.FoobarDelegate
DataStructuresTests.Tester::FoobarEvent
IL_0017: ret
}
.method public hidebysig specialname instance void
remove_FoobarEvent(class DataStructuresTests.FoobarDelegate
'value')
cil
managed synchronized
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.0
IL_0002: ldfld class DataStructuresTests.FoobarDelegate
DataStructuresTests.Tester::FoobarEvent
IL_0007: ldarg.1
IL_0008: call class [mscorlib]System.Delegate
[mscorlib]System.Delegate::Remove(class [mscorlib]System.Delegate,
class
[mscorlib]System.Delegate)
IL_000d: castclass class DataStructuresTests.FoobarDelegate
IL_0012: stfld class DataStructuresTests.FoobarDelegate
DataStructuresTests.Tester::FoobarEvent
IL_0017: ret
}
And then, you have this:
.event class DataStructuresTests.FoobarDelegate FoobarEvent
{
.addon instance void
DataStructuresTests.Tester::add_FoobarEvent(class
DataStructuresTests.FoobarDelegate)
.removeon instance void
DataStructuresTests.Tester::remove_FoobarEvent(class
DataStructuresTests.FoobarDelegate)
}
Does .addon and .removeon stand for +/-? Maybe some of you can
explain
this stuff to me.
When you create an event without accessors in C#, the compiler
generates
a
set of accessors(add_FoobarEvent and remove_FoobarEvent) which
indeed
map to
+ and - on the event. It also generates an underying field which the
accessors can operate on as well as what accessing the event gets
you.
Consider
public event EventHandler Myevent;
//in some method:
Delegate d = MyEvent;
The compiler transforms the access to MyEvent into an access of hte
underlying field it generates. This lets you consider an event as a
normal
field instead of an event property as it actually is. If you want to
write
one your selfe
EventHandler myEventField;
public event EventHandler MyEvent
{
add
{
myEventHandler+= value;
}
remove
{
myEventHandler -= value;
}
}
but you now have to reference myEventFIeld to get the backing
delegate
or to
raise it. MyEvent() won't work.
Thanks.
On Sat, 10 Apr 2004 23:21:15 -0500, Daniel O'Connell [C# MVP]
I've been wondering about the proper way of doing events in .net!
This is what I have right now:
-When an event is used by more than one class, you put it in the
namespace, set the sender to object, and MyEventArgs e.
-When an event is only used by one class, you put it inside that
class,
set the sender to the class type, and MyEventArgs e.
I would recommend placing it in the namespace. I personally
recommend not
placing any type nested in another type unless it needs access to
non-public
members.
namespace Foobar
{
public delegate void FoobyEventHandler(object sender,
FoobyEventArgs e);
public event FoobyEventHandler Fooby;
An event here isn't syntactically legal. Are you sure you are
doing
this?
class Bar
{
public delegate void BarOnFireEventHandler(Bar sender,
BarOnFireEventArgs
e);
public event BarOnFireEventHandler BarOnFire;
}
}
-When an event does not return any data, what is the poind of
having an
instance of EventArgs an in System.EventHandler? EventArgs is
empty and
not used, what is the poind of wasting a little memory on that
object
if
it isn't used? Why isn't System.EventHandler declared as:
It maintains consistency across the system. By defining
EventHandler
with
said two parameters, it established the pattern that every event
has
two
parameters, a sender and a set of event arguments. There is
probably
no
specific reason outside of that.
Beyond that, the memory wasted, if you use best practices, is very
low;
probably no more than 100 bytes per appdomain.
namespace System
{
public delegate EventHandler(object sender);
}
-EventArgs should have been declared as, since it is useless:
public abstract class EventArgs {}
Its not useless, EventArgs is a placeholder for empty arguments.
-The same should have been done with System.Exception to force
lazy
devs
to create their own exceptions:
public abstract class Exception {}
Thats probably true, but it'll never change.