2009-11-03 15 views
5

estoy mirando a la forma de resolver un problema y no estoy siquiera seguro de que esto podría ser posible en absoluto en C# .NET 3.5 &:C# ¿Cómo generar un objeto implementando diferentes interfaces dinámicamente en tiempo de ejecución?

Decir que tengo un número limitado de interfaces, cada uno que describe un procedimiento específico, conjunto de métodos no relacionados. Ahora tengo un número de dispositivos del mundo real en los que cada uno puede implementar solo un subconjunto de estas interfaces.

Durante la configuración de las comunicaciones con estos dispositivos, ellos me dirán qué capacidades tienen. Ahora me gustaría crear un objeto que implementa las interfaces (cada uno se asemeja a una capacidad del dispositivo) de manera que más arriba en mi arquitectura de aplicaciones soy capaz de:

  • código de escritura contra las interfaces mencionadas
  • prueba si ese objeto generado implementa una cierta interfaz para ver si se admiten ciertas acciones

No estoy seguro de qué enfoque utilizar para este problema. ¡Cualquier comentario o enfoque es bienvenido!

+0

En primer lugar, gracias a todos por sus comentarios y sugerencias. ¡Muy apreciado! Bien, creo que debería elaborar un poco más sobre el problema que estoy enfrentando. Tengo un cierto número de capacidades, p. CanMakeCoffe, CanCleanKitchen, etc. Existen algunas capacidades que la mayoría de los dispositivos implementarán, p. CanMakeCoffee. Lo que me gustaría evitar es definir algún lugar de las clases de código fuente para estos dispositivos como en CDeviceOne: ICanMakeCoffee, ICanCleanKitchen CDeviceTwo: ICanMakeCoffee –

+0

Prefiero tener el dispositivo dime cuando se conectan lo que pueden hacer y luego crearía un objeto que se parece a sus habilidades. ¿Tiene sentido? –

Respuesta

3

Pruebe algo como LinFu.DynamicObject.

+0

Muy interesante de hecho. Me gusta especialmente la idea de crear mixin. Estoy un poco indeciso de usar ese tipo de marco para el código de producción ... Tendré que mirar la licencia. De todos modos gracias por eso! –

+0

Tiene licencia como LGPL. Y deberías agradecer a Philip, no a mí :) –

5

Utilice un mocking framework como Moq, RhinoMocks o TypeMock Isolator

Si usted está buscando para hacer algo de nivel inferior, cosas como Castle DynamicProxy podría ser una buena dirección para usted.

+2

Una búsqueda de tipado de patos también puede arrojar resultados. – leppie

+0

@leppie: Muy buen punto. @Timo: si utilizas un lenguaje dinámico como IronPython o IronRuby (o cosas dinámicas relacionadas en C# 4), puedes lograr algo útil (aunque no estarías usando definiciones de 'interfaz' reales y' is' o 'as 'en la implementación –

+0

@leppie: gracias por su sugerencia. Ya he echado un vistazo a la tipificación de pato, pero no estaba seguro de si me ayudaría con el problema. ¡Voy a echar otro vistazo de todos modos! @Ruben: gracias por sus sugerencias para el DynamicProxy. ¡Más interesante! También voy a echar un vistazo más de cerca allí. –

0

Es posible, simplemente no es fácil. Necesita crear una cadena que sea básicamente un archivo fuente y luego crear y usar un CSharpCodeProvider, que luego ordena compilar. Si funciona, puedes acceder manualmente a tus objetos creados a través de la reflexión.

Para el interesado, lo hice hace un tiempo, los detalles son un poco brumosos.

+2

Probablemente sería tan fácil emitir il-code en un ensamblaje dinámico en la memoria. Sin embargo, un marco burlón podría hacer esto más fácil/en menos código. ;) – sisve

1

Quizás no necesite hacer esto tan "dinámico".

¿Has comprobado el patrón Abstract Factory? Parece que básicamente lo que necesita es crear una implementación concreta para cada una de sus interfaces basada en un dispositivo tipo.

No necesita tener una única clase que implemente muchas interfaces, es suficiente con la implementación adecuada de la interfaz específica cuando su código lo solicite.

Cada implementación concreta de su fábrica abstracta puede generar varias implementaciones de interfaz en función de su tipo de dispositivo.

Ejemplo:

public interface IDeviceFactory 
{ 
     ISomething GetSomeInterface(); 
     ISomethingElse GetSomeOtherInterface(); 
} 

y luego se implementa la fábrica específica para cada dispositivo:

public class SimpleDeviceFactory : IDeviceFactory 
{ 
    public virtual ISomething GetSomeInterface() 
    { return Something.Empty; } 

    public virtual ISomethingElse GetSomeOtherInterface() 
    { return new SomeSimpleConreteImplementation(); } 
} 

o tal vez:

public class ComplexDeviceFactory : IDeviceFactory 
{ 
    public virtual ISomething GetSomeInterface() 
    { return new ComplexStuff(); } 

    public virtual ISomethingElse GetSomeOtherInterface() 
    { return new EvenMoreComplexStuff(); } 
} 

Y luego, finalmente, se crea la derecha fábrica para su dispositivo:

public class DeviceFactory 
{ 
    public static IDeviceFactory CreateForDevice(IDevice device) 
    { 
      DeviceType type = device.Type; // or something like this 
      switch (type) 
      { 
       case DeviceType.Simple: 
       return new SimpleDeviceFactory(); 

       case DeviceType.Complex: 
       return new ComplexDeviceFactory(); 

       default: 
       throw new NotImplementedException(); 
      } 
    } 
} 

Tenga en cuenta que también he marcado las implementaciones del método IDeviceFactory como virtual, por lo que puede reutilizar o anular fácilmente interfaces específicas para un dispositivo específico.

+0

¡Gracias Groo, ese es un enfoque directo al problema! Como dije en mi comentario sobre mi pregunta original, me gustaría evitar hacer el código "centrado en el dispositivo" (crear clases para cada dispositivo posible) y tener un objeto creado en base a los comentarios del dispositivo (lo que es capaz de hacer). –

0

.NET 4 podría hacerlo más fácil, puede usar uno de los marcos ya mencionados o seguir la ruta System.Reflection. Encontrará muchas muestras en internet.

He hecho ambas cosas en el pasado. Lanzando mi propio il.Emit cosas y usando un marco (Spring.NET en mi caso). Para cualquier cosa que no sea trivial, use uno de los marcos.

0

También puedes probar con el proyecto Re-mix. Una de las características principales de este proyecto es crear mixins, que le permite agregar interfaces con implementaciones y estado a otras clases. Echar un vistazo este ejemplo:

using Remotion.Mixins; 
using Remotion.TypePipe; 
//... 

public interface ITargetInterface 
{ 
    void DoSomething(); 
} 
// . . . 
public class TargetImplementation : ITargetInterface 
{ 
    public void DoSomething() 
    { 
     Console.WriteLine("ITargetInterface.DoSomething()"); 
    } 
} 
// . . . 
public interface IMixinInterfaceA 
{ 
    void MethodA(); 
} 
// . . . 
public class MixinImplementationA : IMixinInterfaceA 
{ 
    public void MethodA() 
    { 
     Console.WriteLine("IMixinInterfaceA.MethodA()"); 
    } 
} 
// . . . 
public interface IMixinInterfaceB 
{ 
    void MethodB(int parameter); 
} 

// . . . 
public class MixinImplementationB : IMixinInterfaceB 
{ 
    public void MethodB(int parameter) 
    { 
     Console.WriteLine("IMixinInterfaceB.MethodB({0})", parameter); 
    } 
} 

A continuación, puede combinar estos tipos para crear un mixin:

var config = MixinConfiguration.BuildFromActive() 
      .ForClass<TargetImplementation>() 
      .AddMixin<MixinImplementationA>() 
      .AddMixin<MixinImplementationB>() 
      .BuildConfiguration(); 
MixinConfiguration.SetActiveConfiguration(config); 

Por desgracia, no se puede simplemente llamar nuevo en el TargetImplementation y esperar un mixin. En su lugar, debe pedirle a Re-mix que cree una instancia de TargetImplementation para que pueda crear un nuevo tipo para su especificación y crear una instancia. Cuando se le pida una instancia de TargetImplementation, devolverá un mixin que contiene todas las interfaces y clases combinadas.

ITargetInterface target = ObjectFactory.Create<TargetImplementation>(ParamList.Empty); 

target.DoSomething(); 

var targetAsMixinA = target as IMixinInterfaceA; 
if (targetAsMixinA != null) 
{ 
    targetAsMixinA.MethodA(); 
} 

var targetAsMixinB = target as IMixinInterfaceB; 
if (targetAsMixinB != null) 
{ 
    targetAsMixinB.MethodB(30); 
} 
Cuestiones relacionadas