Click here to Skip to main content
15,868,016 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
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
Comments
[no name] 15-Aug-12 11:09am    
Why are you not using MyCustomEventArgs in your method to get the message?
MatthysDT 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.

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:
C#
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:
C#
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
 
Share this answer
 
Comments
Abdul Quader Mamun 15-Aug-12 21:26pm    
good Work!
Sergey Alexandrovich Kryukov 15-Aug-12 21:29pm    
Thank you, Abdul.
--SA
MatthysDT 16-Aug-12 3:05am    
Thank you SA, couldn't have asked for a better response!
Sergey Alexandrovich Kryukov 16-Aug-12 3:35am    
My pleasure. If so, please accept the answer formally (green button) -- thanks.
--SA
MatthysDT 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?
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.
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 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 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)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900