2012-07-13 26 views
9

Mi imbatto in molte situazioni in cui ho dichiarato un'interfaccia generica e successivamente ho avuto bisogno di una versione non generica di questa interfaccia, o almeno di una versione non generica di alcuni dei metodi o delle proprietà su quell'interfaccia. Generalmente dichiarerei una nuova interfaccia non generica e erediterò l'interfaccia generica. Il problema che sto funzionando in in spettacoli nell'esempio che segue:Interfacce generiche e non generiche

public abstract class FormatBase { } 

public interface IBook<F> where F : FormatBase 
{ 
    F GetFormat(); 
} 

public interface IBook 
{ 
    object GetFormat(); 
} 

public abstract class BookBase : IBook<FormatBase>, IBook 
{ 
    public abstract FormatBase GetFormat(); 

    object IBook.GetFormat() 
    { 
     return GetFormat(); 
    } 
} 

Dal momento che l'unico modo per dichiarare l'interfaccia iBook (non generico) è esplicitamente, come si fa a ragazzi andare a questo proposito che lo rende astratto?

+1

Questo non risolve il problema, ma non credi che potrebbe avere un senso per renderlo 'Bookbase : IBook , IBook dove T: FormatBase'? Altrimenti, almeno nel tuo semplice esempio, non c'è niente di meglio che avere 'IBook ' invece di solo 'IBook'. –

+0

Hai ragione. Aggiorno il codice. Ma il problema con l'abstract non generico esiste ancora. – BlueChameleon

+0

Otterrai anche un "'IBook .GetFormat()' nasconde il membro ereditato 'IBook.GetFormat()'. Usa la nuova parola chiave se era nascosto il nascondiglio." avvertimento. Ciò è probabilmente dovuto a una scarsa decisione di progettazione da qualche parte, ma senza ulteriori informazioni è difficile dire quale sarebbe un design migliore. –

risposta

4

Perché non si può scrivere implementazione dell'interfaccia esplicita, invece di dichiarare esso astratto?

public abstract class BookBase : IBook<FormatBase>, IBook 
{     
    public abstract FormatBase GetFormat(); 

    object IBook.GetFormat() 
    { 
     return GetFormat(); 
    } 
} 
+0

Perfetto! Questo e 'esattamente quello che stavo cercando. – BlueChameleon

+0

Ha! Siamo [anche] (http://stackoverflow.com/a/11472335/31158) ora, cowboy ... –

+0

@ Jordão rilascia il trigger :) –

7

Proprio delegato:

public abstract class BookBase : IBook<FormatBase> { 
    public abstract FormatBase GetFormat(); 

    object IBook.GetFormat() { 
    return GetFormat(); 
    } 
} 

Oppure, se si vuole ancora differenziare entrambi i metodi, delegare ad un nuovo metodo:

public abstract class BookBase : IBook<FormatBase> { 
    public abstract FormatBase GetFormat(); 

    public abstract object IBook_GetFormat(); 

    object IBook.GetFormat() { 
    return IBook_GetFormat(); 
    } 
} 

È inoltre necessario new per schivare un "membro ereditato nascondere" warning:

public interface IBook<F> : IBook 
where F : FormatBase { 
    new F GetFormat(); 
} 

Inoltre, potrebbe essere più sensato lasciare le classi di calcolo de Cide sul cemento FormatBase:

public abstract class BookBase<F> : IBook<F> 
where F : FormatBase { 
    public abstract F GetFormat(); 

    object IBook.GetFormat() { 
    return GetFormat(); 
    } 
} 
+1

L'uso di' new' è raramente la risposta giusta. – spender

+0

@spender, non vedo un modo migliore per farlo, vero? –

+0

@spender: usa 'new' o cambia il nome ... Dato che l'OP vuole lo stesso nome, usa' new' o riceve un avvertimento .... Non so voi, ma io non lo so come essere avvertito sulle decisioni _intentional_ che ho preso ... –

Problemi correlati