¿Cargar dinámicamente clases (con comportamiento personalizado) de diferentes ensamblajes?

Estamos construyendo una aplicación para pocos clientes, cada uno tiene sus propios requisitos junto con los similares. También queremos mantener todo el código en la misma aplicación, no ramificarlo, y el IF no es una buena opción ya que estará en todos los lugares.

Planeo tener las clases base para todos. Luego, cada cliente tendrá su propia clase en la que los métodos de anulación harán una lógica especial.

¿Cómo podemos cargar los ensamblajes al comstackr en lugar de hacer esto?

public class BaseClass { public string getEventId() } public class ClassForJohn:BaseClass { [override] public string getEventId() } public class ClassForAdam:BaseClass { [override] public string getEventId() } void UglyBranchingLogicSomewhere() { BaseClass eventOject; if("John"==ConfigurationManager.AppSettings["CustomerName"]){ eventOject = new ClassForJohn(); }else if("Adam"==ConfigurationManager.AppSettings["CustomerName"]){ eventOject = new ClassForAdam(); }else{ eventOject = new BaseClass (); } eventId = eventOject.getEventId(); } 

Así es como cargo complementos (complementos) en uno de mis proyectos:

 const string PluginTypeName = "MyCompany.MyProject.Contracts.IMyPlugin"; /// Loads all plugins from a DLL file. /// The filename of a DLL, eg "C:\Prog\MyApp\MyPlugIn.dll" /// A list of plugin objects. /// One DLL can contain several types which implement `IMyPlugin`. public List LoadPluginsFromFile(string fileName) { Assembly asm; IMyPlugin plugin; List plugins; Type tInterface; plugins = new List(); asm = Assembly.LoadFrom(fileName); foreach (Type t in asm.GetExportedTypes()) { tInterface = t.GetInterface(PluginTypeName); if (tInterface != null && (t.Attributes & TypeAttributes.Abstract) != TypeAttributes.Abstract) { plugin = (IMyPlugin)Activator.CreateInstance(t); plugins.Add(plugin); } } return plugins; } 

Supongo que cada complemento implementa IMyPlugin . Puede definir esta interfaz de la forma que desee. Si recorre todos los archivos DLL contenidos en una carpeta de complementos y llama a este método, puede cargar automáticamente todos los complementos disponibles.

Por lo general, tendría al menos tres conjuntos: uno que contenga la definición de la interfaz, el conjunto principal que hace referencia a este conjunto de la interfaz y al menos un conjunto que implementa (y, por supuesto, referencia) esta interfaz.

¿Cada cliente obtiene su propio archivo exe y config, y hay una DLL compartida? ¿O hay un exe compartido, y cada cliente tiene su propia DLL?

Puede poner el nombre de tipo completo en la configuración de esta manera:

Shared.exe.config:

    

Y ponga AssemblyForJohn.dll en la misma carpeta que su Shared.exe .

Entonces puedes cargarlo dinámicamente en código como este:

Shared.exe:

 var typeString = ConfigurationManager.AppSettings["CustomerType"]; var parts = typeString.Split(','); var typeName = parts[0]; var assemblyName = parts[1]; var instance = (BaseClass)Activator.CreateInstance(assemblyName, typeName).Unwrap(); 

tal vez este ejemplo sea de ayuda

 public MyInterface GetNewType() { Type type = Type.GetType( "MyClass", true ); object newInstance = Activator.CreateInstance( type ); return newInstance as MyInterface; } 

Aquí hay una forma de manejarlo con DI usando Unity .

 IUnityContainer container = new UnityContainer(); string customerNamespace = ConfigurationManager.AppSettings["CustomerNamespace"]; container.RegisterType(typeof(ISomeInterface), Type.GetType(customerNamespace+".SomeImplementation")); // ... ISomeInterface instance = conainer.Resolve(); 

Donde cada cliente tiene su propia implementación de ISomeInterface en un espacio de nombres específico del cliente.

Puede crear una instancia de un tipo externo desde un ensamblaje de esta manera:

 object obj = Activator.CreateInstance( "External.Assembly.Name", "External.Assembly.Name.TypeName"); BaseClass b = (BaseClass) obj; b.getEventId(); 

Almacenarías el nombre del ensamblaje y escribirías tu archivo de configuración o algún otro lugar apropiado.

Yo usaría Unity, pero como una simple fábrica.

Unity Framework: ¿Cómo crear instancias de dos clases desde la misma interfaz?

Usted podría almacenar su

Estoy usando Unity.2.1.505.2 (en caso de que eso haga una diferencia).

   

Aquí está el código DotNet.

 UnityContainer container = new UnityContainer(); UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); section.Configure(container); string myKey = "John"; /* read from config file */ /* with this example, the value should be "myCarKey" or "myTruckKey" */ IVehicle v1 = container.Resolve(myKey); 

Ver:

http://msdn.microsoft.com/en-us/library/ff664762(v=pandp.50).aspx

y

http://www.sharpfellows.com/post/Unity-IoC-Container-.aspx