2

I have following Main method. LocalCabelTV and LocalDishTV classes are in the main application program. The program works fine.

I want to keep LocalCabelTV and LocalDishTV in separate dll files. I wonder then how will I load those classes at runtime? I understand then we'll not use switch but for loop to look for all dll files that implements IVideoSource interface in a particular directory and load those...

Need to know how to dynamically load dlls and create objects and use their methods ?

foreach (string dll in Directory.GetFiles("C:\DLLs\*.dll"))
{
    Assembly assemb = Assembly.LoadFrom(dll);
    ??
}

Following works fine:

static void Main(string[] args)
{
   SmartTv myTv = new SmartTv();

   Console.WriteLine("Select A source to get TV Guide and Play");
   Console.WriteLine("1. Local Cable TV\n2. Local Dish TV");

   ConsoleKeyInfo input = Console.ReadKey();

   switch (input.KeyChar)
   {
      case '1':
          myTv.VideoSource = new LocalCabelTv();
          break;

      case '2':
          myTv.VideoSource = new LocalDishTv();
          break;
   }

   Console.WriteLine(); 

   myTv.ShowTvGuide();

   myTv.PlayTV();

   Console.ReadKey();
}


class SmartTv
    {
        IVideoSource currentVideoSource = null;

        public IVideoSource VideoSource
        {
            get
            {
                return currentVideoSource;
            }
            set
            {
                currentVideoSource = value;
            }
        }

        public void ShowTvGuide()
        {
            if (currentVideoSource != null)
            {
                Console.WriteLine(currentVideoSource.GetTvGuide());
            }
            else
            {
                Console.WriteLine("Please select a Video Source to get TV guide from");
            }
        }

        public void PlayTV()
        {
            if (currentVideoSource != null)
            {
                Console.WriteLine(currentVideoSource.PlayVideo());
            }
            else
            {
                Console.WriteLine("Please select a Video Source to play");
            }
        }


class LocalCabelTv : IVideoSource
    {
        const string SOURCE_NAME = "Local Cabel TV";

        string IVideoSource.GetTvGuide()
        {
            return string.Format("Getting TV guide from - {0}", SOURCE_NAME);
        }

        string IVideoSource.PlayVideo()
        {
            return string.Format("Playing - {0}", SOURCE_NAME);
        }
    }


class LocalDishTv : IVideoSource
    {
        const string SOURCE_NAME = "Local DISH TV";

        string IVideoSource.GetTvGuide()
        {
            return string.Format("Getting TV guide from - {0}", SOURCE_NAME);
        }

        string IVideoSource.PlayVideo()
        {
            return string.Format("Playing - {0}", SOURCE_NAME);
        }
    }
Tamir Vered
  • 10,187
  • 5
  • 45
  • 57
ykhan
  • 55
  • 5
  • Does the same user always have the choice of Dish or Cable? If so, why don't you just include both as references to the project? No need for dynamic detection. – Darren Young Sep 23 '15 at 08:33
  • 1
    You probably want to learn about MEF (https://msdn.microsoft.com/en-us/library/dd460648%28v=vs.110%29.aspx) – jeroenh Sep 23 '15 at 08:39

2 Answers2

1

To load this assembly at runtime and create an object:

Assembly MyDALL = Assembly.Load("DALL"); // DALL is name of my dll
Type MyLoadClass = MyDALL.GetType("DALL.LoadClass"); // LoadClass is my class
object obj = Activator.CreateInstance(Type.GetType("DALL.LoadClass, DALL", true));

For your dynamic Method you can also use Dynamic Method . Its faster than reflection (This method takes only 1/10th time needed by Activator.)

Here is a sample code for creating Object using Dynamic Method.

void CreateMethod(ConstructorInfo target)
{
    DynamicMethod dynamic = new DynamicMethod(string.Empty,
                typeof(object),
                new Type[0],
                target.DeclaringType);

    methodHandler = (MethodInvoker)dynamic.CreateDelegate(typeof(MethodInvoker));
}

Check out these link for more info: Load Assembly at runtime and create class instance

EDIT: As user @taffer mentioned the DynamicMethod.CreateDelegate is much more slower than reflection. So I would use this only if the created delegate is invoked hundreds or thousands of times. Using Activator with a cache is faster. Secondly, Activator is really fast for parameterless constructors, unless you instantiate so many types, which renders the inner small cache useless.

Community
  • 1
  • 1
Yael
  • 1,566
  • 3
  • 18
  • 25
  • You DO NOT want to generate code with `Reflection.Emit` unless you really have to... think about the poor programmer that will replace you and have to learn this code... – Tamir Vered Sep 23 '15 at 08:17
1

You need to load the DLLs with the desire classes and iterate over their types, than look for those that implement IVideoSource and activate them:

public static IEnumerable<IVideoSource> GetVideoSources(List<string> assemblyPathes)
{
    IEnumerable<Assembly> yourAssembliesWithClasses = assemblyPathes.Select(x => Assembly.Load(x));

    IEnumerable<Type> implementingTypes = yourAssembliesWithClasses
        .GetTypes()
        .Where(x => x.IsAssignableFrom(IVideoSource));

    return implementingTypes.Select(x => Activator.CreateInstance(x));
}

Note that Activator.CreateInstance() requires the types to have an empty constructor, if they don't have one you can use, Type.GetUniGetUninitializedObject(Type type) from FormatterServices to initialize them.

Tamir Vered
  • 10,187
  • 5
  • 45
  • 57