raising events by name

B

buu

So, let's say that a user enters an event name in text box, and would like
to raise it..
is it possible to call events by their 'name'?
Is it possible to enumerate events inside app. and to check their names?
 
M

Marc Gravell

Is it possible to enumerate events inside app. and to check their names?
Yes; via reflection or System.ComponentModel. This lets you add/remove
event subscriptions, but it doesn't allow you to invoke the event.
Unless you hack about, you only have access to the *public* part of the
event, which (in C# at least) is just the add/remove accessor methods.
The underlying delegate is *often* a private field, but could also be in
an EventHandlerList, a Dictionary<,>, or on some parent/child instance.

In short, there is no robust single way of doing this for arbitrary classes.

Marc
 
C

Cor Ligthert[MVP]

buu,

As a user enters a name in a box, then that is not an event beside the
entering of the data.

The keys used to enter are events, the action done by what is entered has
nothing to do with an event.

You mix up an event by a simple action that you can do with a conditional
operator.

Cor
 
B

buu

I took a wrong example..
but, lets say that I would like to raise up some events wich I know only by
name
 
C

Cor Ligthert[MVP]

I took a wrong example..
but, lets say that I would like to raise up some events wich I know only
by name
You are not able to raise up an event, it is something that comes from the
OS.

However normally you can call the method. As you need reflection for this,
then there is mostly something terrible wrong in your program. (Or you
should not have the source anymore and are only able to use the DLL. But
that seems strange to me, how do you then know the name).

Cor
 
C

Cor Ligthert[MVP]

Buu,

I forgot to tell, some people comming from a scripting envirorment, try when
they first start with real programs, to use the way they used in the
scripting environment. Scripting has the bad habbit that it is slow and less
secure then pre builded exe and dll's.

However, as you real want this, you can create better array's with words,
and with that when they are equal start a method, instead of going the very
slow and insecure method of reflection.

Cor
 
J

Jon Skeet [C# MVP]

You are not able to raise up an event, it is something that comes from the
OS.

That entirely depends on the event. Look at BindingList<T>.ListChanged,
for example, or the events in my own Push LINQ stuff, or the various
events in ASP.NET.

Conceptually, events have nothing to do with the OS. In a GUI they're
usually tied to something which the operating system has informed the
program about, but that's a very specific example.
However normally you can call the method. As you need reflection for this,
then there is mostly something terrible wrong in your program. (Or you
should not have the source anymore and are only able to use the DLL. But
that seems strange to me, how do you then know the name).

Agreed. The whole point of events is to encapsulate
subscribe/unsubscribe, not raise or replace.
 
C

Cor Ligthert [MVP]

Jon

Conceptually, events have nothing to do with the OS. In a GUI they're
usually tied to something which the operating system has informed the
program about, but that's a very specific example.
<snip>
Agreed, however invoking an event not direct, is because that you can not
control it direct. I tell it in this way just to make it simple. I knew that
once there would be someone who would tell this was not correct.

:)

Cor
 
J

Jon Skeet [C# MVP]

Cor Ligthert said:
<snip>
Agreed, however invoking an event not direct, is because that you can not
control it direct. I tell it in this way just to make it simple. I knew that
once there would be someone who would tell this was not correct.

I'm not sure how bringing the OS into the picture unnecessarily (and
incorrectly) makes it simpler though. To my mind it complicates it for
no reason.
 
D

Dude

Let me give you a very good example where I need to be able to raise
events by using reflection.

I have an application using another UI system than the one provided by
.Net (In my case, a Flash File processed and displayed by a 3rd party
library).

So I implemented my own GUI classes such as button, textbox, etc. that
map the controls of the Flash UI, and implemented a class that
interfaces the Flash with my GUI classes (call it UIEngine).

When I receive events from that Flash file, the cleanest, most elegant
way of making my GUI classes work would have been to be able to raise
the corresponding events from that UIEngine class, using the event name
provided by the Flash library.

Well, with the actual C#, there is no clean way to do it.

Basically it means:

With C#, you can't make your own UI API, you can't implement your own
'OS' in an elegant way. You need to make this work with a workaround,
from the side, using some methods to raise your events for example,
making C# not so elegant on this aspect, as you are forced to write ugly
code to make your thing work in an elegant way.

C++/CLI allows it. VB.Net allows it. Why not C#?
 
J

Jon Skeet [C# MVP]

Dude said:
Let me give you a very good example where I need to be able to raise
events by using reflection.

I have an application using another UI system than the one provided by
Net (In my case, a Flash File processed and displayed by a 3rd party
library).

So I implemented my own GUI classes such as button, textbox, etc. that
map the controls of the Flash UI, and implemented a class that
interfaces the Flash with my GUI classes (call it UIEngine).

When I receive events from that Flash file, the cleanest, most elegant
way of making my GUI classes work would have been to be able to raise
the corresponding events from that UIEngine class, using the event name
provided by the Flash library.

Well, with the actual C#, there is no clean way to do it.

Of course there is - you wrote UIEngine, right? In that case you can
make it raise events however you want. You can use EventList, or store
the delegates in a dictionary. There are loads of ways of doing it
*when you control the event container*.
Basically it means:

With C#, you can't make your own UI API, you can't implement your own
'OS' in an elegant way. You need to make this work with a workaround,
from the side, using some methods to raise your events for example,
making C# not so elegant on this aspect, as you are forced to write ugly
code to make your thing work in an elegant way.

C++/CLI allows it. VB.Net allows it. Why not C#?

Show us the VB.NET and we'll show you the equivalent C#.
 
D

Dude

Well show me how you will get this to compile in c#,
Especially the (RaiseEvent/End RaiseEvent) part.

Public Custom Event MyEvent As EventHandler

AddHandler(ByVal value As EventHandler)
End AddHandler

RemoveHandler(ByVal value As EventHandler)
End RemoveHandler

RaiseEvent(ByVal sender As Object, ByVal e As EventArgs)
End RaiseEvent

End Event
 
J

Jon Skeet [C# MVP]

Dude said:
Well show me how you will get this to compile in c#,
Especially the (RaiseEvent/End RaiseEvent) part.

Public Custom Event MyEvent As EventHandler

AddHandler(ByVal value As EventHandler)
End AddHandler

RemoveHandler(ByVal value As EventHandler)
End RemoveHandler

RaiseEvent(ByVal sender As Object, ByVal e As EventArgs)
End RaiseEvent

End Event

I take it back - that last part is indeed not supported by C#. The rest
is - you specify the add/remove parts.

However, if it's in your own code, it's very simple - you just expose a
method to raise the event:

public event EventHandler Foo;

public void OnFoo(EventArgs e)
{
EventHandler handler = Foo;

if (handler != null)
{
Foo(this, e);
}
}

That's using a field like event, admitttedly. You may find this article
helps:
http://pobox.com/~skeet/csharp/events.html
 
D

Dude

public event EventHandler Foo;
public void OnFoo(EventArgs e)
{
EventHandler handler = Foo;

if (handler != null)
{
Foo(this, e);
}
}

You could actually simplify it to:
public event EventHandler Foo;

public void OnFoo(EventArgs e)
{
if (Foo != null)
Foo(this, e);
}

The point is because you can't implement your own raise method in C#,
you cannot get it from the EventInfo as the returned RaiseMethod is
null. With VB you would actually get a non null method to invoke, making
it possible to invoke using reflection. Using C#, you are forced to
workaround the problem by implementing your own RaiseMyEvent() method
for each event you want to be able to raise this way, which is not as
nice.
 
C

Cor Ligthert[MVP]

I take it back - that last part is indeed not supported by C#. The rest
is - you specify the add/remove parts.
<snip>


Of course it is, although not as elegant as in VB for Net, it is simple
setting and invoking delegates in C#.

(More simple to say to let in a child thread invoke a method in a parent
thread)

It is not meant to call a method which you see something done by beginning
programmers (and I have seen it especially done in C#) where in fact direct
a method can be called, or if it has to be on a non wm message (or any other
message given by a program or whatever), simple to create your own by a
switch while using a dictionary.

Cor
 
C

Cor Ligthert[MVP]

I'm not sure how bringing the OS into the picture unnecessarily (and
incorrectly) makes it simpler though. To my mind it complicates it for
no reason.

--
As this is mostly asked in relation to the WM messages.

A wm message is a simple thing to describe, that a page gives a string back,
which is elevated by the ASPNET program, probably behind the scene in a
dictionary or whatever, that invoke using probably a switch, a method is
something longer to describe and adds in my idea nothing to the subject.

Cor
 
J

Jon Skeet [C# MVP]

Dude said:
You could actually simplify it to:
public event EventHandler Foo;

public void OnFoo(EventArgs e)
{
if (Foo != null)
Foo(this, e);
}

Only if you don't care about thread safety. With the above, if the last
handler unsubscribed after the "if" but before the call to Foo, you'll
get a NullReferenceException.
The point is because you can't implement your own raise method in C#,
you cannot get it from the EventInfo as the returned RaiseMethod is
null. With VB you would actually get a non null method to invoke, making
it possible to invoke using reflection.

Only for those events which actually *do* implement the RaiseMethod
though. I wouldn't expect most events to do that.
Using C#, you are forced to
workaround the problem by implementing your own RaiseMyEvent() method
for each event you want to be able to raise this way, which is not as
nice.

If you wanted, you could store the delegates in a dictionary and have a
single method where you pass in the name of the event you're interested
in. Hardly a problem.
 
J

Jon Skeet [C# MVP]

Cor Ligthert said:
As this is mostly asked in relation to the WM messages.

A wm message is a simple thing to describe, that a page gives a string back,
which is elevated by the ASPNET program, probably behind the scene in a
dictionary or whatever, that invoke using probably a switch, a method is
something longer to describe and adds in my idea nothing to the subject.

WM messages are usually in the context of Windows GUIs, not in ASP.NET.

For instance, you certainly won't get a WM_CLICK message occurring in
the server when a button is clicked in a web page.
 
D

Dude

The link you sent is very relevant. It explains very well what is going
on and what are the options.

For thread safety, most examples I have seen use a Mutex or the lock()
operation to avoid this kind of problem. I think the actual operator =()
of delegates might not be thread safe (could be worth to check).

Concerning the Raise, of course there is no guarantee it will be
overriden. The idea would be for me to be able to override it in
specific class of a UI framework so I know I will be able to call the
raise method on it.

There are workarounds, its just a nice to have that would have made the
code cleaner. It would be effortless for Microsoft to allow overriding
the raise modifier.

The only good reason I see for not supporting this is because of
technical reasons (which I have a hard time figuring out since it works
all good for the other .NET languages)

Not implementing it for the sake of good design or what other reason you
may have does not look relevant to me. It's not Microsoft job to decide
if I should have a nice design or not (who would they be to decide that
raising an event externally means bad design in the first place), their
aim should be to make coding as easy, fast and elegant as possible.
Supporting the Raise Modifier would definitely go that way.

To me it's like if Microsoft would decide to generate compile errors
when finding public fields in a class. Public fields are just horrible
code, but it's not their job to establish design rules for you when it
comes to compile your code.

Not supporting Raise Modifier because it is a bad coding approach is
just as unrelevant as this.
 
J

Jon Skeet [C# MVP]

Dude said:
The link you sent is very relevant. It explains very well what is going
on and what are the options.

For thread safety, most examples I have seen use a Mutex or the lock()
operation to avoid this kind of problem.

You really don't want to hold a lock while calling a delegate, however.
I think the actual operator =()
of delegates might not be thread safe (could be worth to check).

Delegates are immutable, so it's thread safe. On the other hand,
there's no guarantee that you'll get the latest value unless you have a
memory barrier.
Concerning the Raise, of course there is no guarantee it will be
overriden. The idea would be for me to be able to override it in
specific class of a UI framework so I know I will be able to call the
raise method on it.

Right - so instead of doing that, just build a dictionary.
There are workarounds, its just a nice to have that would have made the
code cleaner. It would be effortless for Microsoft to allow overriding
the raise modifier.

Yes - I believe it was omitted for purposes of encapsulation. It makes
the event truly pub/sub.
The only good reason I see for not supporting this is because of
technical reasons (which I have a hard time figuring out since it works
all good for the other .NET languages)

I doubt that it was a technical reason. as you say, it's easy.
Not implementing it for the sake of good design or what other reason you
may have does not look relevant to me. It's not Microsoft job to decide
if I should have a nice design or not (who would they be to decide that
raising an event externally means bad design in the first place), their
aim should be to make coding as easy, fast and elegant as possible.
Supporting the Raise Modifier would definitely go that way.

I disagree. It's entirely Microsoft's job to encourage good design.
There are numerous areas in which C# *doesn't* let you shoot yourself
in the foot.

As it is you're already using reflection - with my suggestion you'd
move *away* from reflection to a neater design in the first place.
To me it's like if Microsoft would decide to generate compile errors
when finding public fields in a class. Public fields are just horrible
code, but it's not their job to establish design rules for you when it
comes to compile your code.

Personally I'd be fairly happy to prohibit public fields, but there we
go.
Not supporting Raise Modifier because it is a bad coding approach is
just as unrelevant as this.

Well, from personal experience I can't say I've *ever* wanted it, and
in your particular case there's a cleaner solution anyway. With your
method, you'd have to code up one Raise for every event. Using my
suggestion you'd use an EventList and have a single Raise method taking
a key. That key can be exposed in a stronger way than just the name -
e.g. as an enum. That allows simple parsing from straight strings, as
well as some compile-time safety if you want to raise the event
directly from code. Wins all round.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top