Using an interface in another assembly

Ok, this is frustrating... I would *think* that this would work, and that there is some way to do it... but I can't seem to get a handle on it.

Anyways, lets say we have any generic application (we'll call it mainApp), and we're trying to load a class from another assembly ( DLL file in this case), and we have the interface for this class, but we do know the class type in the assembly. So we have a DLL project with two files in it:

/// interface file
[IClass.cs]
usign System;
namespace testThis{

    public interface IClass{
        string getString();
    }
}

[/IClass.cs]

[impClass.cs]

using System;
namespace testThis{

public class impClass : IClass{
    public impClass(){}

    public string getStr(){
         return "YAY! It works!";
    }
}
}

[/impclass.cs]

Then in some executable file somewhere, we try and load this assembly somehow. The code I've been trying to use is something like this: (it also includes the interface file in the project)

using System.Reflection;

void loadAssembly(){                  

    Assembly assm = Assembly.LoadFile(Application.StartupPath + "\\test.dll");
    object obj = assm.CreateInstance("testThis.impClass");

   IClass io = obj as IClass;
   string ret  = io.getStr();
}

The problem is that when I call io.getStr(), it returns a null exception. I've tried casting the object directly using (IClass)obj; but that returns an invalid cast exception. I've also tried just directly creating an object of the interface type, but that doesn't work either...  Using reflection you can examine the object and look a the interfaces using GetInterfaces() and you'll see that the interface is indeed there, it just doesn't want to cast to it for some odd reason. Now, when the class and interface are directly in the program, this works just fine...

IClass io = new impClass();
string ret = io.getStr();


So.... any ideas on how I can get this to work? I'm very open to suggestions.
randomperson83Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

BurntSkyCommented:
Is there any reason why you can't just add a reference to the assembly from the second project instead of using reflection?
randomperson83Author Commented:
Yes, because I also have in there somewhere else a mechanism where I can update the DLL file whenever needed from within the program. (Which yes, I realize that the mechanism used here won't let you unload the assembly, but I have other thingies in my actual code using AppDomains and all that fun stuff... ). We're using this in our lab and we want to have the ability to update the clients whenever we need to without ghosting... thus why the need to load the DLL.
BurntSkyCommented:
Have you tried something like this:

Assembly a = Assembly.LoadFrom("test.dll");
impClass i = (impClass)a.CreateInstance("testThis.impClass");
string s = i.getStr();

Step through that with the VS.NET debugger and make sure it 1) loads the assembly and 2) creates the instance correctly.

Also, you can try invoking it indirectly:

Type t = a.GetType("testThis.impClass");
string s = (string)t.InvokeMember("getStr", BindingFlags.InvokeMethod, null, i, null);

On a side note, you must be a Java or C++ programmer; it's considered improper to name public members using camelcase in C#.  (If you plan on writing C# for a while, I'd suggest picking up the Microsoft Press book: Practical Guidelines and Best Practices for Visual Basic and Visual C# Developers)
Fundamentals of JavaScript

Learn the fundamentals of the popular programming language JavaScript so that you can explore the realm of web development.

BurntSkyCommented:
Additionally, if you need the object to be of the interface type explicitly, I think you can change this line:

impClass i = (impClass)a.CreateInstance("testThis.impClass");

to this:

IClass i = (IClass)a.CreateInstance("testThis.impClass");
randomperson83Author Commented:
Yeah, I tried that... no dice.

impClass i = (impClass)a.CreateInstance("testThis.impClass");

Wouldn't work because impClass isn't defined anywhere... only the interface is defined.

IClass i = (IClass)a.CreateInstance("testThis.impClass");

doesn't work either because it throws a Invalid Cast Exception. Even though once again, with examination from Reflection it seems perfecly valid...

The InvokeMember thing doesn't work either... throws a "Object does not match target type" exception.

Though, I might try looking into trying to just keep it as an object without explicitly knowing what it is and invoking it that way somehow...

Yep, C++ programmer :)
randomperson83Author Commented:
As an aside, the CreateInstance obviously works, because of the fact that the object returned can be examined using reflection, and the debugger steps through the constructor. However... it just doesn't like it being casted to the interface type.
BurntSkyCommented:
Where is IClass defined?  It must be defined in the same assembly as the code you're executing, correct?  But then how are you implementing it from the other assembly?  Is it defined in both places?
randomperson83Author Commented:
Project mainApp contains:

form.cs [application]
IClass.cs [interface definition]

Project DLL contains:

impclass.cs [application]
IClass.cs [same file as the other one]

Basically... I'm trying to seperate the implementation from the interface... and since C# has a interface type, it seemed like the logical way to do it... since there aren't any header files that I can include like I would in C++...
BurntSkyCommented:
Ah, that's probably the problem right there.  Regardless of the interface being defined in the same file, once its compiled into the assembly they are different.  Therefore, IClass in one assembly (although defined exactly the same way) is not the same as IClass in the other assembly.  This is why you can't cast it.  What you should do, if you can, is put IClass in yet another assembly (perhaps you have some sort of framework class library it can go in) and reference the assembly from both of the other projects.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
randomperson83Author Commented:
Thats annoying.... but you're right. Does that mean I have to include THAT dll file as well? Hmm... guess I'll have to play with it.

But you're right, I fixed it by putting the IClass.cs in another file, and compiling that to DLL. Then I referenced it in both projects and it all worked nicely.. heh. There's gotta be a way around that somehow.
randomperson83Author Commented:
On another thought here, the thing I don't like about that is that then all the comments we did on the interface are lost. I know MS has comments on all their class libraries... is there a way that we can do the same thing? This is kinda a different question, but its related to the same thing I had, because now we're losing all the comments by making it actually work ;)
BurntSkyCommented:
Unfortunately, I can't imagine there's any way to avoid it.  The framework reads metadata from the assembly to determine if a class implements a particular interface (rather than just checking if the class in question implements the members defined in the interface.)  It's unfortunate that you can't simply reference the assembly, rather than dynamically loading it; that would have made it a lot simpler.

By "comments" do you mean the Xml comments that show up using Intellisense that describe a particular member?  If you put the interface in a separate assembly and reference it, you should still be able to pick up the comment data.  I've actually never been able to figure out how to do it, but I know you're required to set the "Xml Documentation File" path in the Configuration|Build section of the project's property pages.  Then it will create the Xml file containing the definitions of the assembly's members, however, I've been unsuccessful when trying to get VS.NET to pick these up and display them in Intellisense.  I've never looked into it too much though...
randomperson83Author Commented:
Thanks a lot!

I got the comments to work too. You have to place the generated XML file in the same directory as the referenced assembly. The .NET framework puts them in the same diirectories as the dll files themselves... nice.
randomperson83Author Commented:
It also has to be named the same thing as the dll... so if you have test.dll, then test.xml references it. :)
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.