2010-10-04 11 views
6

Ho sviluppato alcuni metodi di estensione per oggetti, che non voglio essere usato/mostrato in intellisense per oggetti che implementano IEnumerable. Concettualmente voglio qualcosa come il seguenteCome specificare un parametro di tipo che NON implementa una particolare interfaccia?

public static T SomeMethod<T>(this object value) where T != IEnumerable 
     { 

     } 

È possibile imporre questo tipo di vincolo comunque in C#?

Modifica

Siamo spiacenti, ho messo la questione in un modo sbagliato. Conosco i vincoli consentiti in C#, quello che voglio sapere è che se c'è un altro modo per realizzare questo?

+0

Hai quattro tipi di contravvenzioni sui generici in C#, e questo non è uno di questi. Non penso sia possibile, ma qualcuno con più esperienza di me dovrebbe confermare questo. –

+0

Con IntelliSense, credo che il meglio che si possa fare per scrivere un commento sia che questo metodo non è disponibile per i tipi che implementano IEnumerable. Non è perfetto, ma meglio di niente. –

risposta

13

Giusto per confermare il commento di Øyvind: non c'è nessun vincolo in C#. Gli unici tipi di vincolo sono:

  • where T : struct (non annullabile tipo di valore di vincolo)
  • where T : class (tipo di vincolo riferimento)
  • where T : SomeClassName (conversione di un particolare vincolo classe)
  • where T : ISomeInterfaceName (conversione un particolare vincolo di interfaccia)
  • where T : U (conversione a un altro vincolo del parametro di tipo)
  • where T : new() (costruttore vincolo senza parametri)

noti che ho separato solo i vincoli di classe e interfaccia specifici come il primo è un vincolo primario e il secondo è un vincolo secondario.

+0

C'è un altro modo di scelta rapida per realizzare questo? –

+2

@Anindya: Non c'è modo di farlo a tempo di compilazione, breve o lungo. Puoi lanciare un'eccezione al momento dell'esecuzione, ma è piuttosto brutto farlo. –

+1

Abbastanza brutto :) E non aiuterà il suo obiettivo di rimuovere il metodo di estensione da IntelliSense. –

0

Questo non è possibile.

1

Questo non è supportato. I vincoli legali sono elencati here.

0

Come altri hanno già detto, non è possibile lavorare, ma è possibile esaminare quali tipi di oggetti si desidera supportare e limitarli a qualche classe/interfaccia che hanno in comune, oppure si può è sufficiente abbandonare la parte generica e scrivere diversi metodi di estensione, quindi è possibile disabilitare IEnumerable.

0

Non si può, e sono d'accordo, è una seccatura, anche se quello che mi sono trovato a desiderare non è tanto quello che stai cercando, quanto l'annullamento sulla base del vincolo (in modo che potrei ad esempio avere un classe e una versione struct dello stesso metodo o classe, e avere quella appropriata usata come applicabile).

Ci sono due casi in cui possiamo ottenere bene.

Uno è il motivo per cui non si desidera utilizzare un metodo di estensione è che è già fornito come metodo di istanza. In realtà lo otteniamo gratuitamente; i metodi di istanza vengono sempre utilizzati al posto dei metodi di estensione (sebbene non sia possibile utilizzarequando si chiama baseClass.method() se esiste solo in derivedClass).

L'altro caso è la selezione di runtime:

public static T SomeMethod<T>(this object value) where T != IEnumerable 
{ 
    if(typeof(T).GetInterface("IEnumerable") != null) 
    { 
    //behaviour appropriate for IEnumerable 
    } 
    else 
    { 
    //other behaviour. 
    } 
} 

E 'non è l'ideale, soprattutto se l'unico "adeguato comportamento per IEnumerable" è un'eccezione, ma può essere sufficiente a volte.

+0

Cosa succede con typeof (T) .GetInterface ("IEnumerable")! = Null. Is è o non è più chiaro? –

+0

@Esben, preso in prestito dal mio pensiero su qualcos'altro, in cui ho dovuto trattare il tipo separatamente dall'oggetto. Sì, 'is'or' as' servirebbe bene e sarà molto più chiaro. –

0

Si può fare qualcosa di simile, ma solo per i tipi che controlli.

dire che si desidera avere un metodo come questo:

public static class XmlSerializableExtension { 
    public static string ToXml(this object self) { 
    // ... 
    } 
} 

Ma non si vuole inquinare ogni oggetto con esso, solo un sottoinsieme di classi.

È possibile ottenere in questo modo:

public interface MXmlSerializable { } 
public static class XmlSerializable { 
    public static string ToXml(this MXmlSerializable self) { 
    // ... 
    } 
} 

Ora, si contrassegna le classi che si desidera questo metodo da applicare con l'interfaccia "mixin":

public class MyClass : MXmlSerializable { 
    // ... 
} 

e apparirà solo in intellisense per queste classi.

Problemi correlati