Come estendere correttamente un'interfaccia con proprietà immutabili per offrire la mutabilità tramite un'altra interfaccia

4

I seguenti frammenti di codice sono semplificati per dimostrare il contesto! Le interfacce e le classi effettive sono POCO con proprietà aggiuntive. I tipi sono parte della libreria su cui sto lavorando, le interfacce sono API pubbliche, le API interne delle classi.

Ho:

  1. un'interfaccia IValue

    public interface IValue
    {
        Int32 Value { get; }
    }
    
  2. 2 diverse interfacce IConfigurableValue (2 rami separati di git) che estendono IValue , vedi più avanti

    public interface IConfigurableValue : IValue
    {
        void CopyFrom(IValue source); // is always part of the interface
    }
    
  3. un'implementazione AutoGeneratedValue

    internal class AutoGeneratedValue : IConfigurableValue
    {
        public Int32 Value { get; set; }
    
        public void CopyFrom(IValue source)
        {
            Value = source.Value;
        }
    }
    
  4. codice che deve accedere al solo getter (tramite IValue ) e al codice che richiede un IConfigurableValue (nessuna implementazione nota in fase di compilazione)

    Gli utenti esterni della libreria possono implementare IValue e IConfigurableValue da soli. Parte del mio codice libreria crea un'istanza di AutoGeneratedValue . Se l'utente fornisce un'attuazione IConfigurableValue personalizzata, viene passata a mia AutoGeneratedValue , l'utente decide se ignorarla o meno. Un'altra parte API accetta un'istanza di IValue e fa qualcosa. Ha solo bisogno di leggere le proprietà dell'istanza. Questa parte dell'API può essere invocata senza richiedere mai alcuna istanza di IConfigurableValue .

Il mio obiettivo per la libreria è a) di offrire metodi che richiedono un'istanza IValue ist e b) metodi per generare automaticamente% istanze diIValue o popolare istanze fornite da IConfigurableValue che possono essere usato per la parte a.

Al momento ho 2 rami con le seguenti definizioni di IConfigurableValue :

  • IConfigurableValue estenderà una IValueConfiguration separata e anche IValue

    public interface IConfigurableValue : IValue, IValueConfiguration
    {
        void CopyFrom(IValue source);
    }
    
    public interface IValueConfiguration
    {
        Int32 Value { set; }
    }
    
  • e un IConfigurableValue che definisce il setter stesso, senza interfaccia aggiuntiva

    public interface IConfigurableValue : IValue
    {
        new Int32 Value { set; }
    
        void CopyFrom(IValue source);
    }
    

Con entrambe le opzioni ho bisogno di lanciare IConfigurableValue in IValue per accedere al getter nella parte b della mia libreria. Con l'opzione no. 1 Ho bisogno di lanciare IConfigurableValue in IValueConfiguration per accedere al setter.

Opzione no. 2 mi nega l'utilizzo tramite un'interfaccia setter-only perché qualsiasi IConfigurableValue è un IValue , con no. 1 Potrei usare IValueConfiguration se ne ho bisogno. - Questo non è un requisito reale della mia API, ma non conosco le future richieste per l'API.

C'è un'altra opzione per raggiungere il mio obiettivo e quale opzione dovrebbe essere preferita?

    
posta ckerth 25.08.2016 - 11:22
fonte

1 risposta

1

Considera solo questo:

public interface IValue
{
    Int32 Value { get; }
}

public interface IConfigurableValue : IValue
{
    void SetValue(Int32 newValue);
}

L'ovvio svantaggio qui è che i chiamanti di IConfigurableValue devono usare una sintassi insolita simile a Java per il setter invece della normale sintassi di C #. Tuttavia, questa soluzione è semplice e facile da capire.

Devi definire CopyFrom come membro dell'interfaccia se la sua implementazione può variare tra diverse classi di implementazione. Se tutte le classi di implementazione utilizzeranno la stessa implementazione di CopyFrom , basta invece definirlo come un metodo di estensione:

public static class ConfigurableValueExtensions
{
    public static void CopyFrom(this IConfigurableValue destination, IValue source)
    {
        destination.SetValue(source.Value);
    }
}
    
risposta data 26.08.2016 - 15:18
fonte

Leggi altre domande sui tag