2016-04-28 89 views
6

Ho un'interfaccia che dichiara alcune proprietà (abbreviate in Id solo nell'esempio) con solo un metodo get. Le classi che implementano questa interfaccia non devono fornire un setter pubblico per questo alloggio:Aggiunta del setter alla proprietà di sola lettura ereditata nell'interfaccia C#

public interface IMetadataColumns 
{ 
    Int32 Id { get; } 
} 

ora ho bisogno di un'altra interfaccia con le stesse proprietà, ma ora tutti devono essere scrivibile pure. Così ho aggiunto una nuova interfaccia che eredita da quella vecchia in cui ogni struttura dispone anche di un setter:

public interface IMetadataColumnsWritable : IMetadataColumns 
{ 
    Int32 Id { get; set; } 
} 

Visual Studio ora sottolinea questo e mi avverte di utilizzare la parola chiave new se nascondere le vecchie proprietà era destinato.


Cosa devo fare ora? Ho classi che implementano l'interfaccia IMetadataColumns che necessita di alcune proprietà per essere di sola lettura, ma ho anche altre classi in cui esattamente le stesse proprietà devono essere anche modificabili.

Credo che nasconde una proprietà suoni in qualche modo non come la strada da percorrere ...

+0

Penso che nascondere la proprietà sia la maniera corretta di andare, le classi che implementano IMetadataColumns avranno ancora solo proprietà read e le classi che implementano IMetadataColumnsWritable avranno la proprietà read/write. –

risposta

11

Quando le interfacce sono coinvolte, la parola chiave new non significa che sia nascondere la proprietà nello stesso senso delle classi.

tua classe che implementa IMetadataColumnsWritable avrà una sola Id, indipendentemente dal fatto che il cast alla base IMetadataColumns interfaccia o no (a meno si aggiunge un'implementazione esplicita per la proprietà di sola lettura - ma questo non è necessario e dovrebbe consentire solo per errori in questo caso).

In altre parole, si potrebbe avere:

// this interface is public, and it allows everyone to read the Id 
public interface IMetadataColumns 
{ 
    int Id { get; } 
} 

// this one is writeable, but it's internal 
internal interface IMetadataColumnsWritable : IMetadataColumns 
{ 
    // we need to use 'new' here, but this doesn't mean 
    // you will end up with two getters 
    new int Id { get; set; } 
} 

// internal implementation is writeable, but you can pass it 
// to other assemblies through the readonly IMetadataColumns 
// interface 
internal class MetadataColumns : IMetadataColumnsWritable 
{ 
    public int Id { get; set; } 
} 

Quindi, a meno che non si implementa in modo esplicito la proprietà di sola lettura come una struttura separata, si avrà solo una singola proprietà, a seconda di quale interfaccia usare per accedervi:

var columns = new MetadataColumns { Id = 5 }; 

var x = (columns as IMetadataColumns).Id; 
var y = (columns as IMetadataColumnsWritable).Id; 

Debug.Assert(x == y); 

Nascondere un membro all'interno della classe utilizzando la parola chiave new, d'altra parte, è quello che vorrei non raccomandare nella maggior parte dei casi, perché in fondo crea un nuovo membro , che sembra essere chiamato lo stesso di un membro diverso nella classe base.

+0

@PatrickHofman: Solo se si implementa l'altro esplicitamente, che non si – Groo

+0

Quindi questo significa che se ho una classe che implementa l'interfaccia scrivibile che usa la parola chiave 'new' per nascondere la dichiarazione di sola lettura, un'istanza di quella classe castata in' IMetadataColumns' avrà una proprietà sottostante differente rispetto a quando è castato su 'IMetadataColumnsWritable' o no? –

+1

No, c'è solo un @ByteCommander –

2

Si dovrebbe infatti utilizzare la parola chiave new qui. Nell'implementazione della classe, è necessario implementare entrambe le proprietà (poiché non si nasconde realmente la proprietà). Se hanno tipi di rendimento diversi, almeno uno di essi deve essere implementato esplicitamente.

public class X : IMetadataColumnsWritable 
{ 
    public int Id 
    { 
     get; 
     set; 
    } 

    // only necessary if you have to differentiate on the implementation. 
    int IMetadataColumns.Id 
    { 
     get 
     { 
      return this.Id; // this will call the public `Id` property 
     } 
    } 
} 
+0

Quindi stai dicendo che non ho bisogno della parte 'int IMetadataColumns.Id {...}' se non c'è logica e la proprietà leggibile e leggibile deve essere la stessa quando si legge il valore? –

+0

Sì, lo è. @ByteCommander –

1

L'implementazione esplicita del getter prevede solo l'inoltro di versioni a una versione pubblica?

int IMetadataColumns.Id { 
    get { 
    return this.Id; 
    } 
} 

public Id { 
    get { … } 
    set { … } 
} 

Si potrebbe trovare la versione pubblica ha bisogno di essere new, ma la versione esplicita saranno raccolti dai riferimenti di tipo IMetadataColumns.

+0

Non c'è bisogno di lanciare il 'this.Id' nell'esplicito' Id'. –

+0

@PatrickHofman Tendo ad includerlo come misura difensiva e di coerenza (anche se a volte non necessario) – Richard

+0

Potrebbe anche causare problemi durante la modifica delle interfacce –