casting problems in c#

  • Thread starter Thread starter Simon X-Session
  • Start date Start date
S

Simon X-Session

Hi !

I hope somebody can help me, i'm completly out of mind.
My problem:

I have a class inherited from Windows.Forms.Control named BasicModule,
which implements an interface named IModule (this has nothing to do
with the Module-Class of the framework. it's selfmade).

Now when I instantiate an object dynamically from an assembly created
from the source of BasicModule, i'm able to cast this object to
Control, but not to IModule, not even to BasicModule.

so that you can imagine something:

public class BasicModule : Control, IModule
{ ... }

public interface IModule
{ ... }

now the critical part:

ModuleEntity selected = (ModuleEntity)trvQueries.SelectedNode.Tag;
object instance = selected.Library.CreateInstance("DAP." +
selected.Description.Class,true);
pnlModule.Controls.Add((Control)instance);
((IModule)instance).DBConnection = dbConnection;

ModuleEntity holds information about the loaded assembly (stored in
member "Library", "DAP" is namespace of project)
pnlModule is a panel to which i want to add the control

it just doesn't work !
the debugger even tells me, that "instance" is of type BasicModule,
but i'm not able to cast it to this class


i also tried to make a abstract base-class, which inherits Controls
and implements IModule
and inherit BasicModule from this base-class
but i also can't cast to that abstract base-class !

i'm freaking out

please help me, i'm in serious trouble if i don't solve the problem
soon


ps: it's an requirement, that i can load any assembly-class, which
implements the IModule interface, at runtime
this is the base of an extensible application which loads specific
dlls described in some xml-configuration-file
so you don't have to rebuild the application when adding new modules
 
Jon Skeet said:
This usually happens if you've got the base class/interface present in
two different assemblies - the dynamically loaded one and the
"driving" one. Put it in just one place, and you should be fine.

i don't know if i understand you right
i need to have the interface in both assemblys, otherwise it wouldn't
compile

well, i coded a little sample program to demonstrate my problem:


(BaseClass.cs)
namespace CastTest
{
public class BaseClass
{
private int x;
public BaseClass()
{
x = 0;
}
public int X
{
set { x = value; }
get { return x; }
}
}
}

(ITest.cs)
namespace CastTest
{
public interface ITest
{
int Square();
}
}

(TestClass.cs)
namespace
{
public class TestClass : BaseClass, ITest
{
public TestClass()
{
X = 5;
}
public int Square()
{
return X*X;
}
}
}


first: test it with normal object instantiation (CastTest.cs)

(Test.cs)
namespace CastTest
{
public class MainClass
{
public static void Main(string[] args)
{
try
{
object instance = new CastTest.TestClass();
int x = ((CastTest.ITest)instance).Square();
// just a test, cast to TestClass
int y = ((CastTest.TestClass)instance).Square();
System.Console.Write("x ok: " + x);
System.Console.Write("\ny ok: " + y);
}
catch (System.Exception e)
{
System.Console.Write(e.Message);
}
}
}
}

compiles and runs fine

second: test it with loading assembly (Test.cs)

(Test2.cs)
namespace CastTest
{
public class MainClass
{
public static void Main(string[] args)
{
try
{
System.Reflection.Assembly as =
System.Reflection.Assembly.LoadFrom("CastTest.dll");
System.Console.Write("Assembly loaded: " +
as.ToString());
object instance =
as.CreateInstance("CastTest.TestClass");
System.Console.Write("Instance created: " +
instance.ToString());
int x = ((CastTest.ITest)instance).Square();
int y = ((CastTest.TestClass)instance).Square();
System.Console.Write(x);
}
catch (System.Exception e)
{
System.Console.Write("\n" + e.Message);
}
}
}
}

i compile the base classes to a library
..\>csc /target:library /out:CastTest.dll BaseClass.cs ITest.cs
TestClass.cs

and compile main class including other cs-file (otherwise it doesn't
compile cause he doesn't know ITest)
..\>csc Test.cs ITest.cs

loading of assembly and instatiation of class works flawlessly, but as
soon as i want to cast the object reference to the interface, it fails
drop the line where i cast to the interface and uncomment the test to
cast to "TestClass"
even this fails in runtime
notive the output of ToString() of instance
it says CastTest.TestClass !!
so this class should be save to be casted
 
Simon X-Session said:
i don't know if i understand you right
i need to have the interface in both assemblys, otherwise it wouldn't
compile

No you don't. You need to add a reference to the assembly which
contains the interface in order to compile against it.

You may well decide to put the interface in a separate (and thus very
small) assembly on its own, and add a reference to that assembly for
both of the other assemblies.

loading of assembly and instatiation of class works flawlessly, but as
soon as i want to cast the object reference to the interface, it fails
drop the line where i cast to the interface and uncomment the test to
cast to "TestClass"
even this fails in runtime
notive the output of ToString() of instance
it says CastTest.TestClass !!
so this class should be save to be casted

No it shouldn't - because if you output GetType()==typeof(ITest) you'll
find they're not the same types. Basically you end up with two separate
types in memory, both for the same type name. The cast is using the
version loaded in its assembly, but the actual type is the one in the
assembly containing the test class.
 
Back
Top