Using interfaces for reflection-loaded classes

G

Guest

I am having problems with casting or converting a class to to an interface
from which it derives. I'm certain that it's due to how it's being loaded,
but I'm not sure how to get past the problem.

Here's a general outline of the architecture. It's oversimplified, but I
think it's enough info to help:

Assembly A.dll
{
interface IMyBase {}
}

Assembly B.dll (references A.dll)
{
class PlugIn : IMyBase {}
}

Assembly C.exe (references A.dll)
{
class InternalClass : IMyBase {}

class MyUI
{
// use IMyBase stuff here
}
}


Now if C.exe loads up an instance of InternalClass, it can cast it to
IMyBase and use it no problem.

If it loads B.dll and creates an instance of PlugIn through reflection I
*cannot* then cast it to an IMyBase.

How can I get access to the dynamically loaded plug in instance's members as
the base interface type? Til now I've been hacking it and just doing things
like getting functions by name, not by using the interface contract, but now
I need to create a handler for an event in the plug in and my hacks are
getting really ugly.

-Chris
 
G

Guest

I'm saying that in C.exe I load up b.dll and get an instance of PlugIn via
reflection. Then this fails:

object instanceLoadedViaReflection;

// load assembly and create instance

IMyBase plugin = instanceLoadedViaReflection as IMyBase;

if(plugin == null) // this is always true

plugin = (IMyBase)instanceLoadedViaReflection; // this always throws


-Chris
 
G

Guest

And to make it all the more frustrating, this gets the Type, which has the
proper name - it's just not convertible:

Type intf = instanceLoadedViaReflection.GetType().GetInterface("IMyBase");

if (intf != null)
{
// the interface exists in the object, as it always gets here
string name = intf.FullName;
// name here is "A.IMyBase" as expected
// but trying to convert it to IMyBase fails
}

-Chris
 
G

Guest

And even more frustrating, if I do the following in the immediate window:

?intf

and ?typeof(IMyBase)

and then diff the two, they are the same - even the same GUID - but this:

?intf.Equals(typeof(IMyBase))

returns false

WTF?

-Chris


And to make it all the more frustrating, this gets the Type, which has the
proper name - it's just not convertible:

Type intf = instanceLoadedViaReflection.GetType().GetInterface("IMyBase");

if (intf != null)
{
// the interface exists in the object, as it always gets here
string name = intf.FullName;
// name here is "A.IMyBase" as expected
// but trying to convert it to IMyBase fails
}

-Chris




I'm saying that in C.exe I load up b.dll and get an instance of PlugIn
via reflection. Then this fails:

object instanceLoadedViaReflection;

// load assembly and create instance

IMyBase plugin = instanceLoadedViaReflection as IMyBase;

if(plugin == null) // this is always true

plugin = (IMyBase)instanceLoadedViaReflection; // this always throws


-Chris


sloan said:
I'm getting ready to leave for the day, but

http://sholliday.spaces.live.com/Blog/cns!A68482B9628A842A!126.entry
I have an example there.

But just to clarify, you saying that in B.dll
the following code fails


PlugIn pi = new PlugIn ();

IMyBase ipi = pi as IMyBase;

if(null!=ipi)
{
ipi.SomeMethod();
}


?




"<ctacke/>" <ctacke[at]opennetcf[dot]com> wrote in message
I am having problems with casting or converting a class to to an
interface from which it derives. I'm certain that it's due to how it's
being loaded, but I'm not sure how to get past the problem.

Here's a general outline of the architecture. It's oversimplified, but
I think it's enough info to help:

Assembly A.dll
{
interface IMyBase {}
}

Assembly B.dll (references A.dll)
{
class PlugIn : IMyBase {}
}

Assembly C.exe (references A.dll)
{
class InternalClass : IMyBase {}

class MyUI
{
// use IMyBase stuff here
}
}


Now if C.exe loads up an instance of InternalClass, it can cast it to
IMyBase and use it no problem.

If it loads B.dll and creates an instance of PlugIn through reflection
I *cannot* then cast it to an IMyBase.

How can I get access to the dynamically loaded plug in instance's
members as the base interface type? Til now I've been hacking it and
just doing things like getting functions by name, not by using the
interface contract, but now I need to create a handler for an event in
the plug in and my hacks are getting really ugly.

-Chris
 
S

Samuel R. Neff

The oversimplified code works fine, assembly B can be loaded through
reflection (Assembly.LoadFile for example) and then class PlugIn can
be cast directly to IMyBase.

So there has to be something different between the oversimplified case
and your actual code. I would suggest either building upon the
oversimplified case so it approaches your real code until it breaks
and seeing what caused the break, or working the other way and try to
comment out the real code until it works. Either way, we can't help
without knowing your code 'cause the sample you provided works fine.

Besides this oversimplified example, we use this type of reflection
loaded plugin system extensively in our applications and have not had
a problem casting instances to their interfaces.

HTH,

Sam
 
G

Guest

I'll look at it further tomorrow, but the "more true" scenario is this:

We have an app (C) that gets the interface from a separate assembly (A).
We have a plug in (B) that also gets the interface from A.

The app loads a class from the plug in. This class exposes a "GetForm"
method. The Form returned from this inherits Form plus implements IPlugIn.
It can be used as a Form, as we're able to display it just fine, however it
just doesn't like that interface. I can get the interface by name, so the
class definitely implements it, but it won't cast. It's like it sees it as
a separate interface, just with coincidentally the same interface name.

-Chris
 
P

Peter Duniho

I'll look at it further tomorrow, but the "more true" scenario is this:

We have an app (C) that gets the interface from a separate assembly (A).
We have a plug in (B) that also gets the interface from A.

The app loads a class from the plug in. This class exposes a "GetForm"
method. The Form returned from this inherits Form plus implements IPlugIn.
It can be used as a Form, as we're able to display it just fine, however it
just doesn't like that interface. I can get the interface by name, so the
class definitely implements it, but it won't cast. It's like it sees it as
a separate interface, just with coincidentally the same interface name.

I really have no practical experience with this sort of thing. However,
the last time something like this came up in this newsgroup, it turned
out to be an issue where the class being used for the cast was just as
you describe: it had the same name, but was from a completely different
assembly.

You should double-check to make sure that the interface that all code is
using is the same interface. That is, all of the code referencing the
interface uses the same assembly, compiled from a single source. The
problem _sounds_ like you may have an issue where you're getting the
interface from multiple places.

Pete
 
S

sloan

I concur.

I've seen that issue as well, where it was the same name, but actually
different classes.

Can you get some extra info about it , using something like ... GetType()
and the full AssemblyName or something like that
(its late and I'm going from memory)
 
G

Guest

Yep, that was it. The project was modified by another developer to put the
plug-in in a separate folder, so it then copied the interface-holding
assembly there too, causing the two projects to be using separate assemblies
for the physical reference.

Adding the interface assembly to the GAC solved the problem.


--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Managed Code in an Embedded World
www.OpenNETCF.com
 
S

sloan

GAC'ing the A.dll seems like overkill.

Can't you just put the compiled version of A.dll somewhere that both
projects can reference?


Either way, you got it figure out.
 

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