Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / New Users / August 2007

Tip: Looking for answers? Try searching our database.

Activator Question

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Dan Dorey - 07 Aug 2007 18:08 GMT
My goal is to pass in an assembly and have the method return an
instance of any classes that inherit from the generic type T.

My problem is that I'm unable to cast from the result of
Activator.CreateInstance(curType) to T even though curType is a
concrete class of T (T is abstract in this case). I'm unsure why I
can't make this cast. In another method where I don't have the
restriction of T being a class, this approch works fine when T is an
interface.

I kind of feel like I'm going about this the wrong way, so if anyone
has suggestions on a better approach, please let me know :)

Thanks,
Dan

public static List<T> GetClassesByClassName<T>(Assembly assembly,
object[] classParams) where T : class
       {
           List<T> ret = new List<T>();

               foreach (Type curType in assembly.GetTypes())
               {

                   if (InheritsFrom(curType, typeof(T)) &&
curType.IsAbstract == false)
                   {
                       if (classParams == null)
                       {

ret.Add((T)Activator.CreateInstance(curType));
                       }
                       else
                       {

ret.Add((T)Activator.CreateInstance(curType, classParams));
                       }
                   }
               }

           return ret;
       }

private static bool InheritsFrom(Type curType, Type targetType)
       {
           bool ret = false;

           while (curType.FullName != "System.Object")
           {
               if (curType.FullName == targetType.FullName)
               {
                   ret = true;
                   break;
               }
               else
               {
                   curType = curType.BaseType;
               }
           }

           return ret;
       }
Jon Skeet [C# MVP] - 07 Aug 2007 18:14 GMT
> My goal is to pass in an assembly and have the method return an
> instance of any classes that inherit from the generic type T.
[quoted text clipped - 8 lines]
> I kind of feel like I'm going about this the wrong way, so if anyone
> has suggestions on a better approach, please let me know :)

Well, instead of InheritsFrom, you'd be better off using
Type.IsAssignableFrom or Type.IsSubclassOf.

However, I don't get any compile-time errors with your code.

Could you post a short but complete program which demonstrates the
problem?

See http://www.pobox.com/~skeet/csharp/complete.html for details of
what I mean by that.

Signature

Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too

Dan Dorey - 07 Aug 2007 19:14 GMT
well interestingly enough, I made a quick test app so I could show you
the problem, but it appears my test app works just fine. Also note
that the casting error I was getting before was at runtime not when
compiling.

I had to use my ugly method of testing for inhertience because
IsSubclass and IsAssignableFrom were returning false for me.
Interestingly IsAssignableFrom returns true if my class Action is NOT
abstract. Clearly I'm missing something about the workings of these
methods.

I'll have to start changing my test app so that it's closer and closer
to the real thing and see when it breaks. Here is the test app and if
you have any thoughts let me know. Thanks for getting me to do the
test app... at least I know it's possible now with this approch.

Thanks,
Dan

*******************************************************************

>From a startup project, you have to add this line of code:

DynamicLoader.GetClassesByClassName<Node>(Directory.GetCurrentDirectory()
+ @"\PluginTester.dll", null);

********************************************************************

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Reflection;

namespace PluginTester
{
   public abstract class Node
   {
       public abstract string NodeID { get; }
   }

   public abstract class Action : Node
   {
       //public abstract string NodeID { get; }
       public abstract string ActionID { get; }

   }

   public class MyAction : Action
   {
       public override string NodeID
       {
           get
           {
               return "MyAction";
           }
       }
       public override string ActionID
       {
           get { return "MyActionID"; }
       }
   }

   public class DynamicLoader
   {
       public static List<T> GetClassesByClassName<T>(string
fileName, object[] classParams) where T : class
       {
           List<T> ret = new List<T>();

           Assembly assembly = Assembly.LoadFrom(fileName);
           foreach (Type curType in assembly.GetTypes())
           {

               if (InheritsFrom(curType, typeof(T)) &&
curType.IsAbstract == false)
               {
                   if (classParams == null)
                   {
                       ret.Add((T)Activator.CreateInstance(curType));
                   }
                   else
                   {
                       ret.Add((T)Activator.CreateInstance(curType,
classParams));
                   }
               }
           }

           return ret;
       }

       private static bool InheritsFrom(Type curType, Type
targetType)
       {
           bool ret = false;

           while (curType.FullName != "System.Object")
           {
               if (curType.FullName == targetType.FullName)
               {
                   ret = true;
                   break;
               }
               else
               {
                   curType = curType.BaseType;
               }
           }

           return ret;
       }

   }

}
Dan Dorey - 07 Aug 2007 19:23 GMT
Well I just copied all the code from my mainline application into the
test app and it works there :S I should be able to figure it out from
here even if it doesn't make sense at the moment.
Jon Skeet [C# MVP] - 07 Aug 2007 19:26 GMT
> well interestingly enough, I made a quick test app so I could show you
> the problem, but it appears my test app works just fine. Also note
> that the casting error I was getting before was at runtime not when
> compiling.

Right. Should the type involved definitely have "worked"?

> I had to use my ugly method of testing for inhertience because
> IsSubclass and IsAssignableFrom were returning false for me.
> Interestingly IsAssignableFrom returns true if my class Action is NOT
> abstract. Clearly I'm missing something about the workings of these
> methods.

Could you give a concrete example of this? It always returns the same
result for me, using:

           Console.WriteLine ("ret={0}", ret);
           Console.WriteLine ("IsAssignableFrom={0}",
                              targetType.IsAssignableFrom(curType));

at the bottom of InheritsFrom.

> I'll have to start changing my test app so that it's closer and closer
> to the real thing and see when it breaks. Here is the test app and if
> you have any thoughts let me know. Thanks for getting me to do the
> test app... at least I know it's possible now with this approch.

My only other request is that you include a suitable Main method so we
know what we're dealing with :) Also, if you use the currently
executing assembly rather than using a filename, it'll make testing
easier.

Signature

Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.