Reflection

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I am trying to dynamically instantiate a class and subscribe to an event that
it throws. I am have no luck finding a proper code sample or documentation
on doing this. Here is what I am attempting and my questions are inline with
the code snippet.

// Load Assembly
Assembly testAssembly =
Assembly.LoadFile@"MyClasses.dll");

// Get the type i am interested in
Type testType =
testAssembly.GetType("MyType");

// Instantiate the object
object obj =
Activator.CreateInstance(testType, args);

// Why does this fail with invalid cast exception??
MyType mytype = (MyType)obj

// Here I am getting the EventInfo
EventInfo ei = testType.GetEvent("_TestCompleted");

// Create the delegate to handle the event fired by testType
Delegate del = new tests.TestCompletedHandler(OnTestComplete);

// Now I want to subcribe to this even
// This fails and i have tried numerous syntax's etc.
// I need clarity on how to subscribt to this event properly.
//
ei.AddEventHandler(??????)
 
jim said:
I am trying to dynamically instantiate a class and subscribe to an event that
it throws. I am have no luck finding a proper code sample or documentation
on doing this. Here is what I am attempting and my questions are inline with
the code snippet.

// Now I want to subcribe to this even
// This fails and i have tried numerous syntax's etc.
// I need clarity on how to subscribt to this event properly.
//
ei.AddEventHandler(??????)

You use the same syntax for specifying the delegate that you would with
a normal event. Here's an example:

using System;
using System.Reflection;

class Test
{
public event EventHandler Foo;

static void Main()
{
EventInfo ei = typeof(Test).GetEvent("Foo");

Test t = new Test();
ei.AddEventHandler (t, new EventHandler (SayHello));
t.Foo("Jon", null);
}

static void SayHello(object sender, EventArgs e)
{
Console.WriteLine ("Hi {0}", sender);
}
}
 
Continuing with my previous code, I actually have a similare line of code:

ei.AddEventHandler(ob, del);

This fails all the time.

One thing I still don't understand and I beleive is the root of my proble,
is why I get the invalid cast exception when unboxing the obj into my
class????
 
jim said:
Continuing with my previous code, I actually have a similare line of code:

ei.AddEventHandler(ob, del);

This fails all the time.

One thing I still don't understand and I beleive is the root of my proble,
is why I get the invalid cast exception when unboxing the obj into my
class????

Yes, that sounds like it almost certainly is the problem. I doubt that
you're unboxing though - just casting. Boxing/unboxing only occurs with
value types.

Perhaps this is your problem?
http://www.pobox.com/~skeet/csharp/plugin.html
 
Do you have any idea why won't it cast properly? I have seen many code
snippets with similar structures so I am at a loss as to what I am doing
wrong. Thus this post.

Thanks for the help
 
Here is the short sample code:
1) Create a new solution with a console and class library projects
2) Paste the code below into a class file in the console project.
3) Coply the Worker WorkerBase, and WorkDoneHandler into the class library
project.
4) Make appropriate references to the class library.
5) Change the Assembly.LoadFile() parameter to your path to the class
library dll

The code has three ways of instantiating the Worker Class:
1) Direct Instantiation - works as expected
2) Reflection Instantiation using Assembly.GetExecutingAssembly() - works as
expteded
3) Reflection Instantiation using Assembly.LoadFile() - fails when calling
CreateInstance and casting.

using System;
using System.Threading;
using System.Reflection;

using ReflectionClasses;

namespace ReflectionTests
{
/// <summary>
/// Summary description for Test1.
/// </summary>
public class Test1
{

[STAThread]
static void Main(string[] args)
{
Console.WriteLine("Test Start");
Assembly wcAssmbly;
Type workerType;
object[] wrkArgs;


/* ******************************************
* Instantiation #1 - Normal
* WORKS FINE!!
* ******************************************
*/
WorkerClass wcl = new WorkerClass("LocalWorker");
wcl._WorkCompleted += new WorkDoneHandler(OnWorkComplete);
wcl.ExecuteWork();



/* ******************************************
* Instantiation #2 - Normal GetExecutingAssembly
* Using Reflection using Assembly.GetExecutingAssembly()
* WORKS FINE!!
* ******************************************
*/
wcAssmbly = Assembly.GetExecutingAssembly();

workerType =
wcAssmbly.GetType("ReflectionTests.WorkerClass");

//Create object
wrkArgs = new object[]{"ReflectionWorker1"};
ReflectionTests.WorkerClass wc =
(ReflectionTests.WorkerClass)Activator.CreateInstance(
workerType,
wrkArgs
);

Delegate del = new WorkDoneHandler(OnWorkComplete);

EventInfo ei = workerType.GetEvent("_WorkCompleted");
ei.AddEventHandler(wc,del);
wc.ExecuteWork();


/* ******************************************
* Instantiation #3 - Normal GetExecutingAssembly
* Using Reflection using Assembly.LoadFile()
* CAST EXCEPTION AT CREATEINSTANCE!!
* ******************************************
*/
wcAssmbly = Assembly.LoadFile(@"C:\...\ReflectionClasses.dll");

workerType =
wcAssmbly.GetType("ReflectionClasses.WorkerClass");

wrkArgs = new object[]{"ReflectionWorker2"};
//Create object FAILS!!!!
wrkArgs = new object[]{"myWorker"};
ReflectionClasses.WorkerClass wc1 =
(ReflectionClasses.WorkerClass)Activator.CreateInstance(
workerType,
wrkArgs
);

Delegate del1 = new WorkDoneHandler(OnWorkComplete);

EventInfo ei1 = workerType.GetEvent("_WorkCompleted");
ei1.AddEventHandler(wc1,del);
wc1.ExecuteWork();

Console.WriteLine("Test end");

Console.ReadLine();
}

public static void OnWorkComplete(WorkerBase worker)
{
Console.WriteLine(
"'" + worker._WorkerName.ToUpper() + "' started " +
worker._WorkStartTime +
" and ended at " + worker._WorkEndTime);
}

}
public delegate void WorkDoneHandler(WorkerBase worker);

public class WorkerClass : WorkerBase
{
public WorkerClass(string workName) : base (workName)
{
_WorkerName = workName;
}

public void ExecuteWork()
{
_WorkStartTime = DateTime.Now;

Console.WriteLine("Working....");

Thread.Sleep(2000);

_WorkEndTime = DateTime.Now;

OnWorkComplete();
}
}

public abstract class WorkerBase
{
public string _WorkerName;
public DateTime _WorkStartTime;
public DateTime _WorkEndTime;

public event WorkDoneHandler _WorkCompleted;

public WorkerBase(string workName)
{
_WorkerName = workName;
}

public virtual void OnWorkComplete()
{
if(_WorkCompleted != null)
{
_WorkCompleted(this);
}
}
}

}
 
jim said:
Here is the short sample code:
1) Create a new solution with a console and class library projects
2) Paste the code below into a class file in the console project.
3) Coply the Worker WorkerBase, and WorkDoneHandler into the class library
project.

And that's the problem - as specified in the article, you then have two
copies of the classes, one in the class library assembly and one in the
console application assembly. Those are entirely different classes as
far as the CLR is concerned.
 
Pardon me for being thick. But I am still not seeing your point.

Commenting out all the code references (which are only there for clarity
pruposes)to the console application Worker class so that we are ONLY
instantiating the one in the class library will STILL cause the cast to fail
at the CreateInstance line.
 
I think i am seeing your point now. So to clarify this to myself I put the
class library with only the code for the WorkerClass, WorkerBase, and
delegate. My console code needs only to instantiate the WorkerClass,
subscribe to the event and call the ExecuteWork().

Now because the delegate is defined in the class libaray i cannot seem to
subscribe properly to the event!

using System;
using System.Threading;
using System.Reflection;

namespace ReflectionTests
{
/// <summary>
/// Summary description for Test1.
/// </summary>
public class Test1
{

[STAThread]
static void Main(string[] args)
{
Console.WriteLine("Test Start");
Assembly wcAssmbly;
Type workerType;
object[] wrkArgs;

/* ******************************************
* Instantiation #3 - Normal GetExecutingAssembly
* Using Reflection using Assembly.LoadFile()
* CAST EXCEPTION AT CREATEINSTANCE!!
* ******************************************
*/
wcAssmbly = Assembly.LoadFile(
@"C:\Documents and Settings\todell\My Documents\Visual Studio
Projects\ReflectionClasses\bin\Debug\ReflectionClasses.dll");

workerType =
wcAssmbly.GetType("ReflectionClasses.WorkerClass");

wrkArgs = new object[]{"ReflectionWorker2"};
//Create object FAILS!!!!
wrkArgs = new object[]{"myWorker"};
ReflectionClasses.WorkerClass wc1 =
(ReflectionClasses.WorkerClass)Activator.CreateInstance(
workerType,
wrkArgs
);

Delegate del1 = new WorkDoneHandler(OnWorkComplete);

EventInfo ei1 = workerType.GetEvent("_WorkCompleted");
ei1.AddEventHandler(wc1,del1);
wc1.ExecuteWork();

Console.WriteLine("Test end");

Console.ReadLine();
}

public static void OnWorkComplete(WorkerBase worker)
{
Console.WriteLine(
"'" + worker._WorkerName.ToUpper() + "' started " +
worker._WorkStartTime +
" and ended at " + worker._WorkEndTime);
}

}
 
jim said:
I think i am seeing your point now. So to clarify this to myself I put the
class library with only the code for the WorkerClass, WorkerBase, and
delegate. My console code needs only to instantiate the WorkerClass,
subscribe to the event and call the ExecuteWork().

Now because the delegate is defined in the class libaray i cannot seem to
subscribe properly to the event!

Well, I *think* I've now got the code the same as yours - although I
needed to add a "using ReflectionClasses;" in order for it to know
about WorkerBase. I got the output:

Test Start
Working....
'MYWORKER' started 20/09/2005 06:59:26 and ended at 20/09/2005 06:59:28
Test end

Is that what was expected?
 
Yes. That is all it does. Spactacular right?
Did you get this result using the reflection CreateInstance LoadFile()?
 
jim said:
Yes. That is all it does. Spactacular right?
Did you get this result using the reflection CreateInstance LoadFile()?

I used the code you'd posted before, with the class library containing
all the worker code.
 
I am lost then. I have never gotten that that cast to work. It always
throws invalid case. Can you please zip me your project and email it to me?
tim_odell @ yahoo . com?
 
jim said:
I am lost then. I have never gotten that that cast to work. It always
throws invalid case. Can you please zip me your project and email it to me?
tim_odell @ yahoo . com?

I think it would make more sense for you to mail me *your* project. In
particular, I haven't actually got a project - just the two files,
which I've compiled from the command line.
 
will do thanks

Jon Skeet said:
I think it would make more sense for you to mail me *your* project. In
particular, I haven't actually got a project - just the two files,
which I've compiled from the command line.
 
Back
Top