2010-06-09 16 views
10

Ho una .net-app che fornisce un meccanismo per estendere l'app con i plugin. Ogni plugin deve implementare un'interfaccia plugin e deve inoltre fornire un costruttore che riceve un parametro (un contesto di risorse).Un'interfaccia può definire la firma di un C# -costruttore

Durante l'istanziazione della classe plug-in, guardo tramite riflessione, se esiste il costruttore necessario e se sì, istanziato la classe (tramite Reflection). Se il costruttore non esiste, faccio un'eccezione che dice che il plugin non può essere creato, perché il costruttore desiderato non è disponibile.

La mia domanda è, se c'è un modo per dichiarare la firma di un costruttore nell'interfaccia plugin in modo che tutti coloro che implementano l'interfaccia plugin debbano anche fornire un costruttore con la firma desiderata. Ciò faciliterebbe la creazione di plugin.

Non credo che una tale possibilità esiste perché penso che una tale caratteristica non cade nel scopo principale per quello che le interfacce sono stati progettati per, ma forse qualcuno conosce una dichiarazione che fa questo, qualcosa di simile:

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

Voglio aggiungere che non voglio cambiare il costruttore per essere senza parametri e quindi impostare il contesto delle risorse attraverso una proprietà, perché questo renderà la creazione di plugin molto più complicata. Le persone che scrivono plugin non sono persone con esperienza di programmazione profonda. I plugin sono utilizzati per calcolare i dati statistici che verranno visualizzati dall'app.


Grazie per tutte le risposte.

Ho deciso, che ho lasciato un'interfaccia perché non mi piace forzare i programmatori di plugin ad ereditare da una classe astratta in modo che lui o lei perda la possibilità di ereditare da una propria classe base . Inoltre, derivare da una classe astratta non garantisce che il programmatore di plugin fornisca realmente il costruttore necessario. Lo rende solo più probabile (il programmatore ha ancora la possibilità di aggiungere solo un costruttore che contiene il parametro desiderato ma che ha anche parametri aggiuntivi, e anche questo è negativo. Vedi i commenti alla risposta di Ken Browning).

Anche se nel mio post ho detto che non voglio una tale proprietà, ho contrassegnato la risposta di Danny Varod come accettata perché penso che nella mia situazione sia la soluzione più appropriata. Grazie a tutti coloro che hanno risposto.

risposta

7

plug-in estensibilità è uno dei miei preferiti ...

Quello che faccio è assicurarsi che il plugin sia implementa l'interfaccia o eredita la classe di base della "presa plug-in" appropriata.

In alcuni punti le classi di base sono più appropriate (se il plug-in è una sorta di X),
in alcune interfacce sono più appropriate (se il plug-in è IX).

Non passo il contesto al costrutto, invece utilizzo una proprietà per quello e un costruttore pubblico senza parametri.

Ciò consente anche una più semplice deserializzazione dei plug-in utilizzando la riflessione.

+0

+1 per l'utilizzo di una proprietà. –

5

No, questo non esiste. Probabilmente stai cercando una classe astratta qui.

7

Le interfacce non possono dichiarare costruttori. Potresti prendere in considerazione l'utilizzo di una classe astratta.

+0

Le classi astratte non possono imporre la creazione di costruttori nelle loro sottoclassi, tuttavia, possono? –

+0

Possono, se si definisce un ctor con parametri, che disabilita la creazione automatica di un ctor senza parametri. da questo, fai rispettare il concatenamento. Non puoi semplicemente derivare da una classe senza chiamare un basettore a meno che la classe base non abbia un ctor senza parametri. – Femaref

+0

@Matthew Scharley, una sottoclasse deve sempre "chiamare" il costruttore in un genitore, quindi se il genitore non ha un costruttore senza parametri, il bambino deve, in qualche modo, ottenere i parametri nel suo costruttore. Ciò può essere applicando lo stesso costruttore al figlio, o forse no, ma è un modo per garantire che le informazioni richieste dal genitore siano date – johnc

1

Sfortunatamente, le interfacce in C# possono contenere solo metodi, proprietà, eventi o indicizzatori.

È possibile utilizzare e astrarre la classe da cui tutti i plug-in erediterebbero. Potresti costringerli a implementare la firma del costruttore in quel caso.

1

L'interfaccia non può dichiarare/imporre un costruttore.

Definire l'interfaccia e creare una classe base astratta che fornisce il più probabile implementazione del costruttore -. Probabilmente solo il salvataggio del contesto risorsa passato in

incoraggiare, ma non richiedono, autori dei plugin per derivano dalla classe base.Potrebbero esserci altri metodi utili che potrebbero essere forniti anche dalla classe base.

Continuare a utilizzare la riflessione per verificare i plug-in.

0

Come altri hanno fatto riferimento, utilizzare una classe astratta per occuparsi dei dettagli dell'impianto idraulico è uno schema comune per ciò che si sta tentando di realizzare. Ecco un disegno che evita la necessità di un costruttore con parametri speciali se il consumatore eredita dalla astratta Plugin classe di 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... 
} 

Il codice deve chiamare Initialize dietro le quinte dopo la creazione del plugin, ma questo dettaglio è nascosto dagli utenti tipici, in quanto generalmente non devono implementare direttamente IPlugin. L'utente tipico può semplicemente definire un discendente del plug-in e lavorare con la proprietà Context.

Si potrebbe anche voler esaminare vari framework di integrazione delle dipendenze (come Ninject), anche se probabilmente sono eccessivi per ciò che si sta facendo. Tuttavia, osservando come funzionano potrebbero darti alcune idee su diversi modi in cui è possibile gestire l'iniezione di dipendenza.

1

In alternativa, si potrebbe provare a utilizzare una fabbrica: fare la firma costruttore di una firma del metodo di un altro tipo:

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

e poi qualcosa di simile (e ho sempre rovinare questa parte se io voglio che sia breve , quindi la modifica):

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