开发者

How do I dynamically point an interface to a specific class at runtime?

As a simple example, I have an xml file with a list of names of classes which actually carry out the work and all implement interface IDoWork with a method Process().

I loop through the items in the xml file. How do I actually dynamically assign the class to the interface from a string name? e.g.

var IDoWork = new "DoWorkType1"();
IDoWork.Process();

<work>
  <item id="DoWorkType1">
  </item>
  <开发者_如何学Go;item id="DoWorkType2">
  </item>
</work>

I want to achieve a plugin type architecture, except the plugin isn't at an assembly level only a class level within my program.


Type t = Type.GetType("DoWorkType1");
IDoWork idw = (IDoWork)Activator.CreateInstance(t);
idw.Process();


If I understand your question, you should register your various classes with the corresponding interfaces with an IoC container, like StructureMap, and use that to dynamically retrieve objects of a specific interface type at runtime.


Is there a specific reason you don't want to use any of a number of dependency injection containers for this? At their core that's really what they do, inject an implementation for a given interface based on some configuration/bootstrapping.


If IDoWork is in the same assembly as DoWorkType1 and DoWorkType2 you can do:

Type t = typeof(IDoWork).GetAssembly().GetType("DoWorkType1");
IDoWork w = (IDoWork)Activator.CreateInstance(t);
w.Process();

Thanks for the corrections everyone!


Basically, you have several options:

-Deserialize your xml as collection of IDowork classes. And execute Process method on each.

-Use manual creation of objects, using Activator.CreateInstance.

-Use some IoC framework. Then you will register all plugins on application start, and execute your action on instances, that your IoC will construct. Something like that.

//On Application Start
Container.Register("DoWorkType1", typeof(DoWorkType1));
Container.Register("DoWorkType2", typeof(DoWorkType2));

//Execute your actions
var instance = Container.Resolve<IDowork>("DoWorkType2");
instance.DoWork()

In case IoC I would recommend you to use AutoFac, StructureMap or Castle.


sorry, decided to do a quick example (whip up a console app):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Interfaces;
using Classes;


namespace Interfaces
{
    public interface IDoWork
    {
        string Name { get; set; }
        string Process();
    }
}

namespace Classes
{
    public class FactoryClass
    {
        private static readonly IDictionary<string, Type> ClassMembers 
            = new Dictionary<string, Type>();
        public static T Create<T>(string s) where T : class
        {
            // if we have 'cached' the type, then use it
            if (ClassMembers.ContainsKey(s))
            {
                return (T)Activator.CreateInstance(ClassMembers[s]);
            }
            // determine the concrete type
            var concreteClass = Assembly.GetExecutingAssembly()
                .GetTypes()
                .Where(t => typeof(T).IsAssignableFrom(t)
                    && t.FullName.ToLower().Contains(s.ToLower()))
                .FirstOrDefault();
            // if we have a match - give it a ping...
            if (concreteClass != null)
            {
                var newUnit = (T) Activator.CreateInstance(concreteClass);
                ClassMembers.Add(s, concreteClass);
                return (T) newUnit;
            }
            // for the sake of the example - return null for now
            return null;
        }
    }

    public class DoWorkType1 : IDoWork
    {
        public string Name { get; set; }
        public bool isNew = true;
        public string Process()
        {
            isNew = false;
            return "It's me - Mr DoWorkType1";
        }
    }

    public class DoWorkType2 : IDoWork
    {
        public string Name { get; set; }

        public string Process()
        {
            return "My turn - Ms DoWorkType2";
        }
    }
}

class Program
{
    public static void Main(string[] args)
    {

        var newWork = FactoryClass.Create<IDoWork>("DoWorkType1");
        Console.WriteLine(newWork.Process());
        newWork = FactoryClass.Create<IDoWork>("DoWorkType2");
        Console.WriteLine(newWork.Process());
        // repeat with DoWorkType1 just to show it coming from dictionary
        newWork = FactoryClass.Create<IDoWork>("DoWorkType1");
        Console.WriteLine(newWork.Process());
        Console.Read();
    }
}

i use a similar approach in an application that takes classnames from a database field and creates the object(s) in a manner similar to the above using the factory class. This simple example of course, has no checks for magic string typos, so that would be an addtional thing to be aware of.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜