2010-06-09 6 views
10

Tengo una aplicación .NET que proporciona un mecanismo para extender la aplicación con complementos. Cada complemento debe implementar una interfaz de complemento y debe proporcionar además un constructor que reciba un parámetro (un contexto de recursos).¿Puede una interfaz definir la firma de un constructor de C#

Durante la creación de instancias de la clase de complemento, miro por reflexión, si el constructor necesario existe y, en caso afirmativo, creo una instancia de la clase (a través de Reflection). Si el constructor no existe, arrojo una excepción que dice que no se pudo crear el complemento porque el constructor deseado no está disponible.

Mi pregunta es, si hay una manera de declarar la firma de un constructor en la interfaz del plugin para que todos los que implementan la interfaz del plugin también deben proporcionar un constructor con la firma deseada. Esto facilitaría la creación de complementos.

No creo que existe esa posibilidad, porque creo que esta característica no cae en el objetivo principal para lo que fue diseñada para las interfaces, pero tal vez alguien sabe una declaración que hace esto, algo como:

public interface IPlugin { 
    ctor(IResourceContext resourceContext); 
    int AnotherPluginFunction(); 
} 

Quiero agregar que no quiero cambiar el constructor para que no tenga parámetros y luego establecer el recurso-contexto a través de una propiedad, porque esto hará que la creación de complementos sea mucho más complicada. Las personas que escriben complementos no son personas con una profunda experiencia en programación. Los complementos se usan para calcular datos estadísticos que la aplicación visualizará.


Gracias por todas las respuestas.

He decidido que dejo que sea una interfaz porque no me gusta forzar a los programadores-complementos a heredar de una clase abstracta para que pierda la posibilidad de heredar de una clase base propia . Además, derivar de una clase abstracta no garantiza que el programador de complementos realmente proporcione el constructor necesario. Lo hace solo más probable (El programador todavía tiene la posibilidad de agregar solo un constructor que contenga el parámetro deseado pero que también tenga parámetros adicionales, y eso también es malo. Vea los comentarios a la respuesta de Ken Browning).

Aunque mencioné en mi publicación que no quiero esa propiedad, marqué la respuesta de Danny Varod como aceptada porque creo que en mi situación es la solución más adecuada. Gracias a todos los que respondieron.

Respuesta

7

Plug-in posibilidad de ampliación es una de mis favoritas ...

Lo que hago es asegurarse de que el plug-in, ya sea implementa la interfaz o hereda la clase base de la "toma de plug-in" correspondiente.

En algunos lugares las clases base son más apropiadas (si el complemento es un tipo de X),
en algunas interfaces son más apropiadas (si el complemento hace IX).

No paso el contexto a la construcción, en su lugar utilizo una propiedad para eso y un constructor público sin parámetros.

Esto también permite una deserialización más sencilla de los complementos mediante la reflexión.

+0

+1 por usar una propiedad. –

5

No, esto no existe. Probablemente estés buscando una clase abstracta aquí.

7

Las interfaces no pueden declarar constructores. Puede considerar usar una clase abstracta en su lugar.

+0

Las clases abstractas no pueden imponer la creación de constructores en sus subclases, ¿o sí? –

+0

Pueden, si defines un ctor con parámetros, que deshabilita la creación automática de un ctor sin parámetros. con esto, aplicas ctor-encadenamiento. Simplemente no puede derivar de una clase sin llamar a un basector a menos que la clase base tenga un ctor sin parámetros. – Femaref

+0

@Matthew Scharley, una subclase siempre debe 'invocar' al constructor en una matriz, por lo tanto, si la matriz no tiene un constructor sin parámetros, el hijo debe, de alguna manera, obtener los parámetros en su constructor. Esto puede ser haciendo cumplir el mismo constructor en el niño, o tal vez no, pero es una manera de garantizar que la información requerida por el padre se dé – johnc

1

Desafortunadamente, las interfaces en C# solo pueden contener métodos, propiedades, eventos o indexadores.

Puede usar la clase abstracta de la que heredarán todos los complementos. Podrías forzarlos a implementar la firma del constructor en ese caso.

1

La interfaz no puede declarar/aplicar un constructor.

Definir la interfaz y crear una clase base abstracta que proporciona la más probable aplicación del constructor -. Probablemente sólo salvar el contexto de recursos aprobada en

alentar, pero no requieren, Plugin autores de deriva de la clase base.Puede haber otros métodos útiles que la clase base también podría proporcionar.

Continuar utilizando la reflexión para comprobar los complementos.

0

Como han mencionado otros, el uso de una clase abstracta para encargarse de los detalles de plomería es un patrón común para lo que está tratando de lograr. Aquí está un diseño que evita la necesidad de un constructor con parámetros especiales si el consumidor hereda a partir del resumen Plugin clase base:

public interface IPlugin 
{ 
    void Initialize(IResourceContext context);  

    //Other methods... 
} 

public abstract class Plugin : IPlugin 
{ 
    protected IResourceContext Context { get; private set; } 

    void IPlugin.Initialize(IResourceContext context) 
    { 
     Context = context; 
    } 

    //Abstract declaration of other methods... 
} 

su código tiene que llamar Inicializar detrás de las escenas después de crear el plugin, pero este detalle es ocultos a los usuarios típicos, ya que generalmente no tienen que implementar IPlugin directamente. Su usuario típico solo puede definir un descendiente Plugin y trabajar con la propiedad Contexto.

Es posible que también desee buscar en varios frameworks de inyección de dependencias (como Ninject), aunque probablemente sean excesivos para lo que está haciendo. Aún así, observar cómo funcionan puede darte algunas ideas sobre las diferentes maneras en que se puede administrar la inyección de dependencia.

1

Alternativamente, puede intentar utilizar una fábrica: hacer que la firma constructora de un método de firma de otro tipo:

public abstract class PluginFactory 
{ 
    public abstract IPlugin Create(IResourceContext context); 
} 

y luego algo así como (y siempre estropear esta parte si yo quiero que sea corta , de ahí la edición):

public class PluginContainer 
{ 
    public IPlugin LoadPlugin<T>(IResourceContext context) where T: PluginFactory, new() 
    { 
     var factory = new T(); 
     return factory.Create(context); 
    } 
} 
Cuestiones relacionadas