469,275 Members | 1,871 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,275 developers. It's quick & easy.

C# win: Using Reflection to create universal event handlers

Plater
7,872 Expert 4TB
I'm a bit boggled by this since I am rather new to using reflection.
I want to attach an event handler via Reflection (which I can do), but I want to NOT have to know the exact event delegate signature.

For an exmaple, I have a .DLL with the following:
Expand|Select|Wrap|Line Numbers
  1. public delegate CustomEnum CustomEventHandler(Socket s, CustomClass c);
  2. public class myclass
  3. {
  4.    public event CustomEventHandler MyEvent;
  5.    //...
  6. }
  7. public enum CustomEnum
  8. {
  9.    //...
  10. }
  11. public class CustomClass
  12. {
  13.    //...
  14. }
  15.  

I want to be able to:
*load the DLL from reflectionlike a plugin would do (done)
*Instanciate an instance of "myclass" (done)
*Attach an event handler to "MyEvent" (trouble)

If the Event signature was of <SomeRegularType> MyEvent(<SomeRegularType> whatever, etc, etc)
I could cheat and create a handler at design time that matches the signature.
BUT the problem is that the customtypes are ALSO kept in the DLL, so I cannot use the types at design time.

I tried creating an eventhandler like this:
object MyEventHandler(object s, object cc);
But the AddHandler() call fails because the delegate signature is not the same.
(I did a test with a regular event that was void MyEvent(string s) and tried using void MyEventHandler(object s) and it also failed)

So I am questioning how this is done? Do I change the signature in the DLL to be of
object MyEvent(object s, object CC) and then do all the .GetType() matching inside the handler function I create?

Seems like there should be a better way to do this.

Anyone have any thoughts?
Nov 10 '08 #1
10 9172
Plater
7,872 Expert 4TB
Well I am still cheating a lot, but I am making progress. I can now create the event I want, using types contained inside
Given (this is kept in plater.dll):
Expand|Select|Wrap|Line Numbers
  1.  
  2. namespace Plater
  3. {
  4. public delegate CustomEnum CustomEventHandler(Socket s, CustomClass c); 
  5. public class myclass 
  6.    public event CustomEventHandler MyEvent; 
  7.    //... 
  8. public enum CustomEnum 
  9.    //... 
  10. public class CustomClass 
  11.    //... 
  12. }
  13. }
  14.  
  15.  

Expand|Select|Wrap|Line Numbers
  1. Assembly asm = Assembly.LoadFrom("plater.dll");
  2. object[] myparams= new object[0];
  3. object myobj = asm.CreateInstance("Plater.myclass", true, BindingFlags.Default, null, myparams, null, null);
  4.  
  5. Type A = asm.GetType("Plater.CustomEnum");
  6. Type B = typeof(System.Net.Sockets.Socket);
  7. Type C = asm.GetType("Plater.CustomClass");
  8.  
  9. EventInfo peEv2 = myobj.GetType().GetEvent("MyEvent");
  10. MethodInfo RRMeth = typeofClassWithGenericStaticMethod.GetMethod("o_MyEvent", System.Reflection.BindingFlags.Static | BindingFlags.NonPublic);
  11. Type[] RRtypestoSend = new Type[] { A,B,C};
  12. MethodInfo RRMethToAttach = RRMeth.MakeGenericMethod(RRtypestoSend);
  13. Delegate peDel2 = Delegate.CreateDelegate(peEv2.EventHandlerType, RRMethToAttach);
  14. peEv2.AddEventHandler(myobj, peDel2);
  15.  
  16. private static void o_MyEvent<A>(A msg)
  17. {
  18.     MessageBox.Show(msg.GetType().ToString()); 
  19. }
  20.  
The eventhandler DOES get triggered as it should.

Places where I still cheat:
1)Knowing the signature of the event (to create the <A,B,C> eventhandler)
2)Knowing how many types are used (to create the type[] to send)
3)Knowing which types to grab (to do the asm.GetType(string) )

Now, knowing 1) pretty much tells you 2) and 3), but I still think there still should be a way to map an event to a function of maybe:
object myfunc(params object[] paras)
Visual Studio has to know how to read an event and decide on the signature parameters in order to do its auto-create for the eventhandler.
Nov 13 '08 #2
balabaster
797 Expert 512MB
Feel free to tell me if I'm missing what you're asking:

Custom event args usually hold relevant data to the event, and they should inherit from System.EventArgs - if the coder follows standards, which I'm certain you do :oP

So that will allow you the ability of attaching a handler without knowing the correct signature. However - it won't allow you access to the custom properties of e.

a la:
eventhandler MyGenericEventHandler(object Sender, EventArgs e)

object.event += MyGenericEventHandler

In order to access the custom properties, you're going to need to cast e to its native type...which we can't know until we reflect on it.

I've run into this situation before where I needed to be able to cast an object as a type only known at runtime and I came up against a wall. I'll have another play and see what I can come up with but from previous experience I'm doubtful I'm going to be successful...

Or are you trying to grab the event handler that's already defined inside the class and attach it to the parent application? Maybe I'm just not following quite what you're after...
Nov 13 '08 #3
balabaster
797 Expert 512MB
Here's a rather amusing thread that's trying to achieve the same thing - albeit for a different purpose. It's mostly amusing because the person trying to assist seems to completely miss the point of the person trying to get assistance and they spend many posts running around in circles before coming up with no suitable conclusion...

But agreed, this is a situation where you would need this ability.

Although, I guess you could use GetProperty and SetProperty on the reflected object - that should work... which is what they allude to. Not sure if it'll work though yet as I haven't tried it...
Nov 14 '08 #4
balabaster
797 Expert 512MB
I'm not sure if you've come across this yet - but it may be a pointer in the right direction:

http://msdn.microsoft.com/en-us/library/system.reflection.eventinfo.addeventhandler.aspx
Nov 14 '08 #5
Plater
7,872 Expert 4TB
Custom event args usually hold relevant data to the event, and they should inherit from System.EventArgs - if the coder follows standards, which I'm certain you do :oP
While I AM a big fan of coding to standards, the DLL is written for (and needs to continue to work on) an limited system Compact framework, where reflection isn't really feasable.

Perhaps I am a bit to vague for generallity sake.
I wrote a webserver in the form of a dll for a project at work.
The dll has a class that handles all the socket business of reading in the http request and building a custom request object (also contained in the dll).
This class exposes TWO events with the following signatures
void NotifyMessage(string msg)
Plater.ThreadState RequestReceived(Socket s, Plater.RequestObject)

Plater.ThreadState, Plater.RequestObject are contained only in the DLL.

Now with my last post I was able to cheat, and do the Assembly.Load(), create an instance of my class and attach eventhandlers to each event, partially because I knew that I gould call a .GetType() on the ThreadState and other objects, and partially because i abused the generics properties on a method.

Now this is functional for what I was after, I was just wondering for a more universal implementation.
I just want my program to go "hey, the httplistener.dll is here, I might as well run a webserver" or "no dll, guess i will carry on without serving webpages"


EDIT:
Not sure why I am being a helmet and thinking I need to use Reflection in the CE version, it will have a legitamate reference to the dll and can use the types like normal.
I suppose I should rewrite the events to match standard handlers, the event that requires a return value: I can create a custom eventargs that has an object inside it, then I can change that object and read it back again at the palce where i called the event, to mimic a return value right?
Nov 14 '08 #6
balabaster
797 Expert 512MB
EDIT:
Not sure why I am being a helmet and thinking I need to use Reflection in the CE version, it will have a legitamate reference to the dll and can use the types like normal.
I suppose I should rewrite the events to match standard handlers, the event that requires a return value: I can create a custom eventargs that has an object inside it, then I can change that object and read it back again at the palce where i called the event, to mimic a return value right?
I reread your post 3 times before you put that edit and could've sworn I was missing something in your reasoning for needing reflection in the CE version... all the CE version is doing is passing the DLL, right? The version that's being passed the DLL is doing all the work, so yeah, I'd modify the object so that it's coded using the standard whereby e inherits from System.EventArgs and presto you're home free...
Nov 14 '08 #7
Plater
7,872 Expert 4TB
home free...
"Home free" being that I don't need to cheat with the event handlers per-say.
I did discover I rather like this:
Expand|Select|Wrap|Line Numbers
  1. public static Dictionary<string, object> GetProperties(object ReflectedObject)
  2. {
  3.     Dictionary<string, object> retval = new Dictionary<string, object>();
  4.     if (ReflectedObject != null)
  5.     {
  6.         MemberInfo[] mems = ReflectedObject.GetType().GetMembers();
  7.         foreach (MemberInfo mi in mems)
  8.         {
  9.           if (mi.MemberType == MemberTypes.Property)
  10.           {
  11.             string name = mi.Name;
  12.             object o = ReflectedObject.GetType().InvokeMember(name, BindingFlags.GetProperty, null, ReflectedObject, null);
  13.             retval.Add(mi.Name, o);
  14.           }
  15.         }
  16.     }
  17.     return retval;
  18. }
  19.  
  20.  
I know there is a .GetProperties on the Type, but I did it this way in case I wanted some other form of members in there too
Nov 14 '08 #8
balabaster
797 Expert 512MB
Yep... looks like it should work pretty well. You can attach a generic handler, grab e and then just reflect over it to grab the properties as necessary.
Nov 14 '08 #9
balabaster
797 Expert 512MB
Hey man - did you get this working in the end? If so, what did you do?
Nov 17 '08 #10
Plater
7,872 Expert 4TB
It got put on hold for now. It was what I was doing in my spare time at work. Projects have picked up.

The plan is still to re-write the DLL to use the standards event formula. Haven't gotten around to playing with the eventargs as a return statement as well.
Nov 17 '08 #11

Post your reply

Sign in to post your reply or Sign up for a free account.

Similar topics

2 posts views Thread by D. Patterson | last post: by
13 posts views Thread by Charles Law | last post: by
14 posts views Thread by Hamed | last post: by
5 posts views Thread by Chris | last post: by
3 posts views Thread by =?Utf-8?B?ZWFndWlsYXI=?= | last post: by
reply views Thread by suresh191 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.