Activator.CreateInstanceFrom problem

  • Thread starter Thread starter CKR Rajesh
  • Start date Start date
C

CKR Rajesh

Hi,

I have 2 dlls on which i have the same class MyClass defined. Say A.dll and
B.dll

The classes have a function (but different functionality)
void f();

I use .Net late binding using Activator.CreateInstanceFrom method to
dynamically call the method f() in either dll.

But I see that once i successfully call the f() method of either of the dll,
I am not able to call the f() method in the other dll even if
I pass the other dll's name as the parameter to CreateInstanceFrom method.
Always f() from the dll which got executed first is always getting
executed...

Am i missing something?

Raj
 
CKR Rajesh said:
I have 2 dlls on which i have the same class MyClass defined. Say A.dll and
B.dll

The classes have a function (but different functionality)
void f();

I use .Net late binding using Activator.CreateInstanceFrom method to
dynamically call the method f() in either dll.

But I see that once i successfully call the f() method of either of the dll,
I am not able to call the f() method in the other dll even if
I pass the other dll's name as the parameter to CreateInstanceFrom method.
Always f() from the dll which got executed first is always getting
executed...

Am i missing something?

Rather than passing the other DLL's name, try using Assembly.GetType on
the appropriate loaded assembly, and then creating an instance using
Activator.CreateInstance passing in the actual type.
 
Yes, that was what i did earlier... same results!

Note that types with exact same name exist on both the assemblies. But I
wonder why that creates a prob....

-Raj
 
this is the code strip


Assembly m_oAssembly = Assembly.LoadFrom(assemblySource);
Type m_oTypeClass = m_oAssembly.GetType(classname,false);

MethodInfo m_oMethodInfoRequestInitialize =
m_oTypeClass.GetMethod("Initialize",System.Reflection.BindingFlags.Public
|System.Reflection.BindingFlags.Instance);

object m_oClassInstance = Activator.CreateInstance(m_oTypeClass);
m_oMethodInfoRequestInitialize.Invoke(m_oClassInstance,m_oRequestArguments);

Thanks in advance

Raj
 
Hi Jon,

Here it is

Step 1
------

Create a dll out of the following code. call it a.dll

namespace SampleNS
{
public class SampleObject
{
[DllImport("kernel32.dll")]
public extern static int Beep(uint frequency, uint duration);

public void TestFunction()
{
Beep(2000,1000);
return;
}
}
}

Replace the line Beep(2000,1000) with Beep(500,1000) complie it to b.dll.
Now you have 2 dlls having same class SampleNS.SampleObject but with
different functionality for TestFunction.


Step 2
------

Create a test console application

private void callit(string fullassemblypath)
{
Assembly m_oAssembly = Assembly.LoadFrom(fullassemblypath);
Type m_oTypeClass = m_oAssembly.GetType("SampleNS.SampleObject",false);
MethodInfo m_oMethodInfoRequestFunction =
m_oTypeClass.GetMethod("TestFunction");

object m_oClassInstance = Activator.CreateInstance(m_oTypeClass);
m_oMethodInfoRequestFunction.Invoke(m_oClassInstance,null);
}

On the main write the following lines.

callit("c:\\temp\\a.dll");
callit("c:\\temp\\b.dll");

Let me know if you want any further information.

Thanks a lot

Raj
 
CKR Rajesh said:
Here it is

Well, that's actually *still* not what I asked for. Why only quote
*part* of the driver application? Why not just cut and paste a
*complete* one, which I've asked for twice?

I actually changed the code to write "A" or "B" to the console rather
than beeping - it's easier to tell the difference, you don't need to
add an extra "using" directive for the DllImport, etc.

However, I then tried it and ran it, and it worked absolutely
perfectly.

Here's what I did (and an example of what I mean by a short but
*complete* example):

A.cs:
using System;

namespace SampleNS
{
public class SampleObject
{
public void TestFunction()
{
Console.WriteLine ("A");
return;
}
}
}

B.cs:
using System;

namespace SampleNS
{
public class SampleObject
{
public void TestFunction()
{
Console.WriteLine ("B");
return;
}
}
}

Test.cs:
using System;
using System.Reflection;

class Test
{
static void Main()
{
CallTestFunction("a.dll");
CallTestFunction("b.dll");
}

private static void CallTestFunction(string fullassemblypath)
{
Assembly dll = Assembly.LoadFrom(fullassemblypath);
Type type = dll.GetType("SampleNS.SampleObject",false);
MethodInfo method = type.GetMethod("TestFunction");

object instance = Activator.CreateInstance(type);
method.Invoke(instance,null);
}
}

Compilation:
csc /target:library A.cs
csc /target:library B.cs
csc Test.cs

Running and output:
c:\test>test
A
B

So, please try the above and see whether it does the same for you. If
it does, you need to work out where the difference between my code and
yours is...
 
Hi,

Thanks a ton for your efforts Jon.

The program you sent works as expected.

BUT

I can repeat my scenario if I do the following. (Please do the exact same
steps)

Use only one cs file. say A.cs. (I have attached the comple source codes
below)

1. Compile it to a.dll [ csc /target:library A.cs ]
2. Copy a.dll to b.dll [ copy a.dll b.dll ]
3. Make modification to the WriteLine statement on a.dll and save it.
4. Compile a.dll again [ csc /target:library A.cs ]
5. Copy the a.dll and b.dll to some other directory (other than where
Test.exe is residing)
6. I have made 2 test programs test1.cs and test2.cs - different of calling
order.

If i run test1 i get
A
A

If I run test2 i get

B
B


Let me know if you could reproduce it.

Note: Dont use /out:a.dll option to build the dlls or use ren function to
rename the dlls. You have to do a *copy*..

I hope that i am not overlooking something and would really appreciate your
help.

-Thanks again

Rajesh


A.cs:
using System;

namespace SampleNS
{
public class SampleObject
{
public void TestFunction()
{
Console.WriteLine ("A"); //Change when you compile it 2nd time
return;
}
}
}

Test1.cs:
using System;
using System.Reflection;

class Test
{
static void Main()
{
CallTestFunction("c:\\temp\\dlls\\a.dll");
CallTestFunction("c:\\temp\\dlls\\b.dll");
}

private static void CallTestFunction(string fullassemblypath)
{
Assembly dll = Assembly.LoadFrom(fullassemblypath);
Type type = dll.GetType("SampleNS.SampleObject",false);
MethodInfo method = type.GetMethod("TestFunction");

object instance = Activator.CreateInstance(type);
method.Invoke(instance,null);
}
}



Test2.cs:
using System;
using System.Reflection;

class Test
{
static void Main()
{
CallTestFunction("c:\\temp\\dlls\\b.dll");
CallTestFunction("c:\\temp\\dlls\\a.dll");
}

private static void CallTestFunction(string fullassemblypath)
{
Assembly dll = Assembly.LoadFrom(fullassemblypath);
Type type = dll.GetType("SampleNS.SampleObject",false);
MethodInfo method = type.GetMethod("TestFunction");

object instance = Activator.CreateInstance(type);
method.Invoke(instance,null);
}
}


Steps
-----

csc /target:library A.cs
copy a.dll c:\temp\dlls\b.dll

[Make change to a.cs]

csc /target:library A.cs
copy a.dll c:\temp\dlls\a.dll

csc test1.cs
csc test2.cs


Running and output:
test1
A
A

test2
B
B
 
CKR Rajesh said:
Thanks a ton for your efforts Jon.

The program you sent works as expected.

BUT

I can repeat my scenario if I do the following. (Please do the exact same
steps)

Right. Gotcha. The problem is in copying DLLs to different names - the
DLL itself internally says what its name is, in the manifest.

The solution is just not to do that, to be honest. Why do you think you
*need* to be able to just copy the DLLs to different filenames?
 
Jon,

I have to maintain 2 versions of the same dll.

One a basic version which i will complile and copy to a directory.

As i continue to develop the dll with new features, changes to business
logic, i will copy it to different folder.

I use the dll from a extended SQL stored procedure and this is how the whole
thing is architected to work :-(

The sql stored procedure will take a parameter on which base directory to
load the dll from.. thatz where i BANG!!

regards,

Rajesh
 
Further to my previous post,

Actually, In my application, all the dlls will be named the same.. only the
directory where they are loaded from differs.

Raj
 
CKR Rajesh said:
I have to maintain 2 versions of the same dll.

So use proper naming, including version numbering - I believe the
problems will then go away.
 
Right. Gotcha. The problem is in copying DLLs to different names - the
DLL itself internally says what its name is, in the manifest.

The solution is just not to do that, to be honest. Why do you think you
*need* to be able to just copy the DLLs to different filenames?

I have just done the same thing. I need to dynamically load different
versions of the same class, but fortunately there are not too many
different versions so I create a new appdomain for each different
version.
 
What Perplexes me even more is the fact that if i to load the classes in
some different order,
it works.. but on the reverse order it does not.

I think something is not consistent on how CLR decides whether a type is
already loaded or not..

I will look into loading the versions on different app domains..

Do you have any sample code for me to take a look?

Thanks,

-Raj
 
CKR Rajesh said:
What Perplexes me even more is the fact that if i to load the classes in
some different order,
it works.. but on the reverse order it does not.

I think something is not consistent on how CLR decides whether a type is
already loaded or not..

I will look into loading the versions on different app domains..

Do you have any sample code for me to take a look?

No, I'm afraid I don't, off-hand. I suspect that *just* giving them
different version numbers will be enough though. You probably won't
even have to specify the version number in the loading code.
 
Back
Top