Click to See Complete Forum and Search --> : Casting Problem when loading from dll


trobert
July 25th, 2002, 02:22 AM
Hi

I am trying to load at runtime a class from a dll,
knowing an interface that the class implements.

I can load and create an instance of that class,
but only as an Object... I cannot convert it to
my interface.

The error is: System.InvalidCastException

The code is:

Assembly a=Assembly.LoadFrom(("a.dll");

Type theType = a.GetType("Type1");

Type interfaceType=theType.GetInterface("iType1");
Console.WriteLine("implements {0}",interfaceType);

Object o=Activator.CreateInstance(theType);
Console.WriteLine("loaded as an object: {0}",o);

iType1 i = (iType1) o;
Console.WriteLine(i);

Both the dll and the exe have the same namespace,
and they both know the interface iType1. And both
the interface and the class are public...

Thanks in advance,

jparsons
July 25th, 2002, 10:22 AM
How is the interface setup? Is there one interface and the other has a refernce to the project with the Interface?

trobert
July 25th, 2002, 10:31 AM
I don't understand your question.

The interface is just an interface, that the class implements.
When I use GetInterface, it says that the class implements
my interface, but when I want to cast it doesn't want anymore.

To be more explicit, I'll include the code for the interface and
class.

public interface iType1
{
}

public class Type1 : iType1
{
}

and that's it... I compile it and make a dll then ...

jparsons
July 25th, 2002, 11:53 PM
Originally posted by trobert
I don't understand your question.

The interface is just an interface, that the class implements.
When I use GetInterface, it says that the class implements
my interface, but when I want to cast it doesn't want anymore.

To be more explicit, I'll include the code for the interface and
class.

public interface iType1
{
}

public class Type1 : iType1
{
}

and that's it... I compile it and make a dll then ...

Sorry I wasn't clear. I just wanted to make sure that you weren't defining the same interface twice ( once in each assembly )

trobert
July 26th, 2002, 01:00 AM
You might be right. I include the interface in both
assemblies, because the dll needs it to implement
it, and the exe needs it to cast.
But the namespace is the same for everybody.

And I don't know if it is possible to reference an
interface from an assembly... probably not.

By the way, can I cast to a variable that is a instance
of Type?

trobert
July 26th, 2002, 07:43 AM
Solved the problem.

Thanks a lot jparsons, you were right.
I know c++ and java, but I am kind of new
with c#. So I didn't understand very well
in the beginning about the references...

So thanks a lot.

mperisic
August 19th, 2002, 04:36 PM
I have been having the exact same problem. I didn't have the same interface defined twice in the two assemblies, but I referenced the dll assembly and used the interface referenced in the dll assmbly for casting. I still got the casting error. Do the interface and class have to be in the same namespace? Any other helpful infromation would be appreciated. Thanks, Marko

trobert
August 19th, 2002, 05:14 PM
Hi Marko,

My mistake, if I recall well, was that when I was compiling using csc I included the file with the interface in both dll. I didn't know then to use /r in csc :)

I understand that you don't have the same problem...

About the namespace, I had only one namespace, but I don't think there would be any problem... still you have to use the complete name of the class or interface (namespace.class) when casting or implementing the interface.

I can't tell you more... if you still can't solve it, maybe you can post your code...

Good luck, Robi

mperisic
August 20th, 2002, 03:32 PM
here is my class:

namespace ComponentLibrary1
{
/// <summary>
/// Summary description for Class1.
/// </summary>
public class Component1: object, ILayoutComponent
{
public Component1()
{
MessageBox.Show("Hello");
}

void ILayoutComponent.Calculate()
{
}
}
}

here is my interface:

namespace ComponentLibrary1
{
public interface ILayoutComponent
{
void Calculate();
}
}

this builds into ComponentLibrary1.dll.

Here is my usage:

Assembly asm;
asm = Assembly.LoadFrom("..\\..\\..\\ComponentLibrary1\\bin\\Debug\\ComponentLibrary1.dll");
object obj = asm.CreateInstance("ComponentLibrary1.Component1");;

ILayoutComponent lc = (ComponentLibrary1.ILayoutComponent)obj;
lc.Calculate();

The DLL is specified in the exe assemnbly as a reference.

Note that I pruposly didn't new it from the reference since I want to specify the implementation to be loaded at runtime through a path string.

I hope this clarifies the situation and somebody can tell me what's wrong. Basically I want to have an interface in my exe that I can use to communicate to a dll library of implementations of this interface, but I wan't to be able to specify the dll at runtime. Typical add-in design.

Thanks in advance,

Marko

trobert
August 20th, 2002, 06:56 PM
I didn't try your example, and I might be wrong ... but I have some comments on your code...

First of all I don't see any reason why you would need to inherit from object... still there is no problem if you do so (but it is something that is automatically happening - every class inherits).

The second comment is that when you are implementing the interface you write like this:

void ILayoutComponent.Calculate()

It seemed strange to me... I am used with java and c++, but it works, still you can't declare it for example
public virtual void ILayoutComponent.Calculate() and I think you might need to do so if you want to inherit even more from Component1.

You can simply write:

public virtual void Calculate() //it understands that it is the method that you want to implement.

And the last comment which might help, I wrote about it in my previous post too, is that you have to use the full name when you say that you want to implement the interface:

public class Component1: ComponentLibrary1.ILayoutComponent

I didn't check this, but for me it seems common sense to be like this, and I believe that the error should be when you compile the class because the compiler doesn't know who is the interface.
Also in the exe you say:
ILayoutComponent lc = (ComponentLibrary1.ILayoutComponent)obj;
You should say:
ComponentLibrary1.ILayoutComponent lc = (ComponentLibrary1.ILayoutComponent)obj;

Hope it helps, and good luck again :)
Robi

P.s: If still doesn't work, post also the way you compile...

Arild Fines
August 21st, 2002, 06:09 AM
Originally posted by trobert
The second comment is that when you are implementing the interface you write like this:

void ILayoutComponent.Calculate()

It seemed strange to me... I am used with java and c++, but it works, still you can't declare it for example
public virtual void ILayoutComponent.Calculate() and I think you might need to do so if you want to inherit even more from Component1.

You can simply write:

public virtual void Calculate() //it understands that it is the method that you want to implement.

This is called explicit interface implementation and is used to disambiguate when you are implementing multiple interfaces that have methods with the same name. But it is not necessary in this case.

trobert
August 21st, 2002, 06:41 AM
Ok Arild :)
I saw that coming, I thought about that.

But still, I see a problem:

let's say I have a base class which implements 2 interfaces that have one common method. So I use this way. And let's say I also want to inherit from this base class. And let's say I want to have that method public and overridable. What do I do?

Because in the declaration of the interface I can't put the public or virtual keyword in front of the method (I really don't know why), and if a method is not virtual you can't inherit it.

I didn't look into this a lot, because I didn't need this, yet... maybe you know more... please let me know.

Thanks, and best regards
Robi

mperisic
August 21st, 2002, 04:17 PM
I'm posting this as an attempt to keep this thread on topic. I am not completly stuck to the specifics of the implementation, and that is not as important ot me as the goal that I'm trying to achieve.

Namely, I want to be able to have an interface ILayoutComponent that has a number of pures in it. I want to make many Component classes that implement this interface that can reside across multiple DLLs, and also I want to be able to specify a DLL to be loaded at runtime that would contain a class that implements this interface. An example would be a drawing program. You have a DLL with a Circle and Line classes implementing ILayoutComponent. Then you should be able to speicify at runtime, hey here is a new DLL that has a Triangle and Square components implementing the same interface and you shouldn't have to recompile the main exe.

My implementation was an attempt to do that. The explicit interface implementations are not a problem i think. Also, in a lot of places you'll see just ILayoutComponent instead of the full namespace.interface reference, since I have the using directive on the top of the file which I haven't included in the post (sorry). As far as the namespaces go, I think that if it compiles, then it shouldn't be a problem.

The problem is that I have a class that legally implements an interface. This interface is legally referenced in another module. The object is legally created, and the constructor shows a message box "Hello" when the objectis created confirming that the desired class has been instantiated. But when I try to cast the object to the exact interface that it implements (trough a reference) then it complains. To me this is mystical and I have no clue what I'm doing wrong.

Again, thanks for your posts guys, but unfortunately the problem still exsits and I am completely stuck.

Oh one more thing, VERY WEIRD!!!

If I use the the new <reference class> approach:

Component1 comp = new Component1;

and then:

ILayoutComponent lc = (ILayoutComponent)comp;

IT WORKS!!!

But if I use the assembly to create the object then it doesn't work:confused:

And, also the derivation from object was just another attempt to solve the problem by stabbing it in the dark.

I hope you have more ideas. I'm stuck.

Cheers,

Marko

trobert
August 21st, 2002, 06:01 PM
Please post also what you didn't post earlier... the way you are referencing the dll.

About the "compiling ok" => "no problem" I don't agree... because it would compile very well if it can see the interface code, but it would generate another assembly in the exe... It's just an ideea... it will be clearer after you post more from the code.

mperisic
August 22nd, 2002, 12:26 PM
Here is a zip with the whole solution with two assemblies, one os the class library the other one ia sample exe that is supposed to instantiate the Component1 class form the class library and cast it to the ILayoutComponent.

trobert
August 23rd, 2002, 01:48 PM
Hi Marko,

I solved your problem...
I told you before. In OptySistem (in the exe) you should not include ComponentLibrary1 with the using keyword because it compiles it again and it consideres that they are different classes (or interfaces). Instead using only the reference and using everywhere Project.interface. In your code it was converting to ComponentLibrary1.ILayoutComponent and than you were trying to convert it implicitly to an ILayoutComponent.

So do like this:

exclude the line "using ComponentLibrary1;"

and change the line
"ILayoutComponent lc = (ComponentLibrary1.ILayoutComponent)obj;"
with

"ComponentLibrary1.ILayoutComponent lc = (ComponentLibrary1.ILayoutComponent)obj;"


Best regards,
Robi

mperisic
August 23rd, 2002, 02:06 PM
Robi, thanks man, you've been spending a lot of time on this, but unfortunately still, after making the changes as you suggested, it still doesn't work for me. Can you send me a zip with my solution that you modified to work. Maybe I'm missing something.

I removed the using directive, and am using namespace.interface exactly as you specified in your post. Still the freakin' invalid cast :mad: .

Again, if you can post the modified working solution, I'd very much appreciate it.

Cheers,

Marko

trobert
August 24th, 2002, 05:24 AM
Hi again Marko,

Don't worry I hadn't spent a lot of time... :)

Here is what was wrong:
In my last post I omited to tell you something. I was not able to build your solution because (at least I think that is the cause) I have .Net Beta 2 and it was telling me that can't use System.Byte (even thou it wasn't use in the project) and that I should reinstall the .Net. So I just compiled the library (it worked) and then copied the dll in the same directory with the form1.cs for a easier path and compiled the exe manually :
csc /target:exe Form1.cs /r:ComponentLibrary1.dll
and it worked.

Now, today when i read your post I was intrigued why on your computer it does not work and I made a solution (exactly like yours - I had to make anouther one because of the "Byte problem") and indeed it didn't work ;) - famous InvalidCast Exception.

So here is what happens:

We have built the library, so under \componentlibrary\debug we have the dll. Then we build the exe. If at the reference properties there is the setting to make a local copy, it copies the dll, this time in the \opti\debug directory, where the exe is. However when you compile with the command line csc, if the directory is not the same, it does not make a copy.

Anyway the thing is that when you use the name of a class or of an interface, in your exe or in your dlls, he expects to find the dll in the directory where the exe lies (probably some other win/Net directories too).

So try using asm = Assembly.LoadFrom("ComponentLibrary1.dll");

But if you want to have the dlls in another directory I think that a good practice, would be to create a dll with all the interfaces and this dll will be in the same directory as the exe, and then all the dlls and the exe to be compiled with a reference to this dll.

Hope my post wasn't very boring and I really hope it helps ;)
By the way if I am wrong with anything that I have said, I would be happy if anyone corrects me.

Good luck,
Robi