Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
See more: C#3.0 DLL Events Generics , +
My project uses latebinding to register a DLL that fires an event.
Within the DLL the event uses a custom class for it's Event arguments to add additional info, e.g. "Message".
 
In other words the class within the DLL should resemble this:
 
//DLL Project:
public class MyCustomEventArgs : EventArgs
{
    public string message;
 
    // Rest of the class body...
}
 
However, within my main project, my receiving event method has no knowledge about the "MyCustomEventArgs" type, and therefor my method merely receives a normal EventArgs, as follows:
 
//Main project, (late binds the DLL):
public void receivedMessage(object sender, EventArgs e)
{
    //Here I want to be able to extract the "Message" string from e, but how?
}
 
In this method I want to expose the type of "e" and create an object of that type.
I know this must be possible, but the solution eludes me.
 
Thank you in advance!
Posted 15-Aug-12 5:56am
MatthysDT6.3K
Comments
Wes Aday at 15-Aug-12 11:09am
   
Why are you not using MyCustomEventArgs in your method to get the message?
MatthysDT at 15-Aug-12 11:18am
   
Hi Wes Aday, like I said, there is no such class (MyCustomEventArgs) in my project since the DLL (whic does have that class) is referenced using late binding. Then you may ask why don't I just create such a class? I could, but if possible this project must be generic for different types of DLL's, but I will resort to that option if all else fails.
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

The idea is very simple. You almost got it, should just think about it.
 
The kind of late binding you use is of the level of plug-in (your "registered" DLL) and the plug-in architecture. You need to look at it as at the whole architecture, and it all will be clear to you. The think is: the host application is never totally agnostic the the plug-in but is agnostic to the implementation detail. The concrete type of event arguments is not one of them. Also, for assignment of event arguments, classical OOP principles apply. And I appreciate you idea on "late binding": this has a deep analogy in late binding as it is understood in OOP.
 
Plug-in architecture is a pretty interesting paradigm, unlike client-server and other rather primitive concepts. You have a host application and some plug-ins. You need to have some plug-in API to recognize some classes and members throw reflection, to use them in the host application. In general case, the host application also provides some plug-in API and its implementations to the plug-ins, so a plug-in and a host application implement their plug-in related interfaces and pass to each other the interface references to those implementation.
 
Now, let's remember that there is no such thing as a miracle. The interfaces are declared somewhere. It can be a separate assembly referenced by both the host and all plug-in implementations, but it can fully reside in the host assembly. (It's important to understand that when you load or reference some assembly, the difference between "EXE" and "DLL" is totally insignificant; those are nothing more then file naming conventions; the files can have any names; you can always reference a host assembly by plug-in.) So, the event argument type should be defined in the same place where the plug-in interfaces are, so both host and plug-in assemblies could use it (quite apparently). These and only these event argument types can serve as a design-time type on the host part. As to the run-time type… I'll consider it later, but it depends on what you want to do with them. But before we go there, let me tell you that the reflection approach Philip Stuyck suggested won't give you much. With reflection, you can discover additional members, but how would you know its semantic meaning?
 
So, let's finally go back to the plug-in derived event argument types. You can apply the principle of classic OOP here. You need to isolate "what to do with it" for some member from "how to do it" which is known to the plug-in. However, you need to stay in the framework of this concept. In particular, you should not try to move derived types back to the plug-in interface, tag the types and try down-casting.
 
Consider this. In the plug-in interfaces:
abstract class PluginEventArgs : EventArgs {
    void KnowWhatToDoWithIt() {
        Info = KnowHowToDoIt();
        // use Info
    }
    protected abstract string KnowHowToDoIt();
    internal string Info; //string is lame, but this is only for the sample
}
In plug-in:
class ThisPlugInEventArgs : PluginEventArgs {
    protected override string KnowHowToDoIt() {
        // use someField
        // use something else
        return // something
    }
    MyType someField;
}
 
Very roughly — just to give an idea.
 
Good luck,
—SA
  Permalink  
Comments
Abdul Quader Mamun at 15-Aug-12 21:26pm
   
good Work!
Sergey Alexandrovich Kryukov at 15-Aug-12 21:29pm
   
Thank you, Abdul.
--SA
MatthysDT at 16-Aug-12 3:05am
   
Thank you SA, couldn't have asked for a better response!
Sergey Alexandrovich Kryukov at 16-Aug-12 3:35am
   
My pleasure. If so, please accept the answer formally (green button) -- thanks.
--SA
MatthysDT at 28-Aug-12 6:52am
   
Hi Sergey
 
When I read your solution I thought I understood it, but I'm only getting to the implementation of it today, and I'm having a hard time.
 
In your example above, where would the file for "abstract class PluginEventArgs" be located, and how should I reference it in both my main project and my plugin?
 
Must it be an abstract class, or can it also be an interface?
Sergey Alexandrovich Kryukov at 5-Sep-12 2:39am
   
It should be either in the host assembly, and then all the plug-in assemblies should reference the host assembly (as I explained, it's not a problem to reference an EXE). Alternatively, you can create a separate assembly for all common declarations and reference it by both host application and all plug-ins.
--SA
MatthysDT at 5-Sep-12 3:07am
   
Thanks Sergey. You are going to be terribly disappointed in me, but due to deadlines and other time-constraints I solved this with reflection. It's not pretty, but it works. Hopefully I'll have time again to revisit your solution within the next two weeks.
Sergey Alexandrovich Kryukov at 5-Sep-12 3:40am
   
If there are problems, we can discuss them later...
Good luck,
--SA
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

You need an extra dll (library) that acts like a bridge between your dynamically loaded dll and your application. Only the common types, that are used or meant to be used by both your application and the dynamically loaded dll should move to this third dll.
This way you do not have to replicate class definitions.
Other solutions would involve reflection. But actually if withing your application you want to get the message, you kind of already have a dependency.
So the answer is to create a common custom eventargs in a library.
  Permalink  
Comments
Sergey Alexandrovich Kryukov at 15-Aug-12 20:04pm
   
Not completely agree.
 
First, there is absolutely no need to introduce another DLL. It's perfectly legal to reference the host application assembly by plug-in assemblies. Having it is very convenient for some cases, excessive for others.
 
I agree that event arguments should be common to both kinds of assemblies, but in principle, extension is possible.
 
And finally, reflection won't help much, by the reasons I explained in Solution 2 -- please see.
 
(I did not vote this time.)
 
Cheers,
--SA
Philip Stuyck at 16-Aug-12 8:29am
   
I did vote for you ;-)
I also did not think reflection was the answer here. I was kind of argueing against it.
I answered how I would do it, it is always possible someone else has a better solution. In the end that is good for the one who asked the question, and for whoever sees the better solution.
 
regards,
Philip

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



Advertise | Privacy | Mobile
Web02 | 2.8.1411022.1 | Last Updated 15 Aug 2012
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100