Home All Groups Group Topic Archive Search About

Checking that an event has handlers added to it - using Reflection

Author
27 Nov 2007 5:07 PM
jehugaleahsa@gmail.com
Hello:

I am creating a simple class library for simplifying reflection.

I am creating an EventWrapper class that allows programmers to treat
it like an event (minus the operator overloading).

I am concerned with how to check that handlers have been added to the
event prior to raising it.

For instance,

if (TextChanged != null)
{
    TextChanged(this, EventArgs.Empty);
}

tests whether there are any handlers prior to raising the event. How
can I do this with the EventInfo class?

Thanks!

Author
27 Nov 2007 5:55 PM
Marc Gravell
Basically there is no robust way of doing this... your cited code
masks a compiler trick - a hidden delegate field. EventInfo points to
the accessors, not the implementation.
It is (commonly) the *field* (sitting behind the accessors) that has
the value, and you'd need to check that. But sometimes the field is
developer-generated (with custom add/remove accessors) and sometimes
there *is* no such field (perhaps using EventHandlerList). Or perhaps
it does something even more esoteric - registers subscribers in a
centralised class for some reason.

Marc
Author
27 Nov 2007 6:03 PM
jehugaleahsa@gmail.com
On Nov 27, 10:55 am, Marc Gravell <marc.grav***@gmail.com> wrote:
> Basically there is no robust way of doing this... your cited code
> masks a compiler trick - a hidden delegate field. EventInfo points to
> the accessors, not the implementation.
> It is (commonly) the *field* (sitting behind the accessors) that has
> the value, and you'd need to check that. But sometimes the field is
> developer-generated (with custom add/remove accessors) and sometimes
> there *is* no such field (perhaps using EventHandlerList). Or perhaps
> it does something even more esoteric - registers subscribers in a
> centralised class for some reason.
>
> Marc

It sounds like I should just let an error happen then. What would be
the benefit of masking it with a try {} catch {}. Would the hide
errors that took place in the event handlers? or would it just hide
that the event didn't have any listeners?
Author
27 Nov 2007 7:32 PM
Marc Gravell
> It sounds like I should just let an error happen then. What would be
> the benefit of masking it with a try {} catch {}. Would the hide
> errors that took place in the event handlers? or would it just hide
> that the event didn't have any listeners?

To be honest, I'm confused as to how you are going to (robustly) do
*anything* useful (other than subscribe/unsubscribe) with an
EventInfo. If you are thinking of using the GetRaiseMethod(), then
note the remark on MSDN:
<q>This method returns a null reference (Nothing in Visual Basic) for
events declared with the C# event keyword or the Visual Basic Event
keyword. This is because the C# and Visual Basic compilers do not
generate such a method.</q>

http://msdn2.microsoft.com/en-us/library/1a4k4e35.aspx

Marc
Author
27 Nov 2007 7:58 PM
jehugaleahsa@gmail.com
On Nov 27, 12:32 pm, Marc Gravell <marc.grav***@gmail.com> wrote:
Show quote
> > It sounds like I should just let an error happen then. What would be
> > the benefit of masking it with a try {} catch {}. Would the hide
> > errors that took place in the event handlers? or would it just hide
> > that the event didn't have any listeners?
>
> To be honest, I'm confused as to how you are going to (robustly) do
> *anything* useful (other than subscribe/unsubscribe) with an
> EventInfo. If you are thinking of using the GetRaiseMethod(), then
> note the remark on MSDN:
> <q>This method returns a null reference (Nothing in Visual Basic) for
> events declared with the C# event keyword or the Visual Basic Event
> keyword. This is because the C# and Visual Basic compilers do not
> generate such a method.</q>
>
> http://msdn2.microsoft.com/en-us/library/1a4k4e35.aspx
>
> Marc

I will have to test this. Thank you for bringing that to my attention.

Ah . . . you are right. MSDN is right. How the heck will I be able to
raise events for dynamically generated code?
Author
27 Nov 2007 8:02 PM
Marc Gravell
Maybe if you post how you expect to eventually consume the completed
EventWrapper (i.e. your use-case) we might suggest the best solution?
Author
27 Nov 2007 10:46 PM
jehugaleahsa@gmail.com
On Nov 27, 1:02 pm, Marc Gravell <marc.grav***@gmail.com> wrote:
> Maybe if you post how you expect to eventually consume the completed
> EventWrapper (i.e. your use-case) we might suggest the best solution?

On Nov 27, 1:02 pm, Marc Gravell <marc.grav***@gmail.com> wrote:
> Maybe if you post how you expect to eventually consume the completed
> EventWrapper (i.e. your use-case) we might suggest the best solution?

Here is the gist of what I am trying to do.

We have lots of business objects to make for lots of projects. Right
now the most time-consuming thing is the creation of the business
objects, writing each of their properties, writing all their SQL and
all the other gobbledy gook.

I want to make a tool that allows the developer to pick columns from
tables (which I have already done) and have it pull out the correct
type, do string length/other data verification, and write base-line
SQL. I have everything I need to do that now. I wrote a reflection
class that can execute generated code. I have code that builds C# and
compiles it.

Now, generally, I don't intend to run the generated Assemblies, or
generate them. My main intent is to create the source code, which I
have already done. However, I am currently in the process of creating
an XML-based format that will allow me to configure B.O.s and have the
effects take place instantly without needing to recompile. The problem
comes when my . . . wait a minute!

Actually, now that I think about it, you can only raise an event
inside a class anyway! My source code generator should be responsible
for creating code for raising events, not the EventInfo class. The
only thing you really should be able to do to a reflected Event *is*
add or remove handlers, which my code already supports.

I can't think of a good reason to allow reflection to raise events.
Thank you for the verification. Now I can get this code generator to
work!

Thanks, you may have just helped me save my company a lot of time and
money.

!Travis
Author
28 Nov 2007 8:28 AM
Marc Gravell
Show quote
On 27 Nov, 22:46, "jehugalea***@gmail.com" <jehugalea***@gmail.com>
wrote:
> On Nov 27, 1:02 pm, Marc Gravell <marc.grav***@gmail.com> wrote:
>
> > Maybe if you post how you expect to eventually consume the completed
> > EventWrapper (i.e. your use-case) we might suggest the best solution?
>
> On Nov 27, 1:02 pm, Marc Gravell <marc.grav***@gmail.com> wrote:
>
> > Maybe if you post how you expect to eventually consume the completed
> > EventWrapper (i.e. your use-case) we might suggest the best solution?
>
> Here is the gist of what I am trying to do.
>
> We have lots of business objects to make for lots of projects. Right
> now the most time-consuming thing is the creation of the business
> objects, writing each of their properties, writing all their SQL and
> all the other gobbledy gook.
>
> I want to make a tool that allows the developer to pick columns from
> tables (which I have already done) and have it pull out the correct
> type, do string length/other data verification, and write base-line
> SQL. I have everything I need to do that now. I wrote a reflection
> class that can execute generated code. I have code that builds C# and
> compiles it.
>
> Now, generally, I don't intend to run the generated Assemblies, or
> generate them. My main intent is to create the source code, which I
> have already done. However, I am currently in the process of creating
> an XML-based format that will allow me to configure B.O.s and have the
> effects take place instantly without needing to recompile. The problem
> comes when my . . . wait a minute!
>
> Actually, now that I think about it, you can only raise an event
> inside a class anyway! My source code generator should be responsible
> for creating code for raising events, not the EventInfo class. The
> only thing you really should be able to do to a reflected Event *is*
> add or remove handlers, which my code already supports.
>
> I can't think of a good reason to allow reflection to raise events.
> Thank you for the verification. Now I can get this code generator to
> work!
>
> Thanks

No problem, but on this occasion I'm genuinely not sure I did
anything! For reference the common pattern is:

public event SomeEventHandler SomeEvent; // optionally bespoke add/
remove

protected void OnSomeEvent(...) { // args perhaps by delegate
signature
  // code that fires SomeEvent
}

then you can simply find you EventInfo and then look for a MethodInfo
based on On{TheName}

Marc
Author
28 Nov 2007 8:28 AM
Marc Gravell
(and perhaps virtual depending on scenario)

AddThis Social Bookmark Button