2009-02-11 5 views
10

ho appena scritto un'istruzione if nelle linee diÈ un buon uso di ExtensionMethod?

if (value == value1 || value == value2 || value == value3 || value == value4) 
    //do something 

e mi infastidisce che devo sempre ripetere il 'valore ==' parte. Secondo me questo non serve a nulla se non renderlo difficile da leggere.

ho scritto il seguente ExtensionMethod che dovrebbe rendere sopra scenario più leggibile:

public static bool IsEqualToAny<T>(this T value, params T[] objects) 
{ 
    return objects.Contains(value); 
} 

Ora posso scrivere semplicemente

if (value.IsEqualToAny(value1, value2, value3, value4)) 
    //do something 

È questo un buon uso di un ExtensionMethod?

EDIT:

Grazie per tutte le grandi risposte. Per la cronaca: ho mantenuto il metodo. Mentre il suggerimento che si può semplicemente utilizzare new []{value1,value2,value3,value4}.Contains(value) è vero, ho semplicemente preferisco la lettura di questo tipo di istruzione if da sinistra a destra (se questo valore è uguale a uno di questi invece di se questi valori contengono questo valore). Avere un altro metodo mostrato in intellisense su ogni oggetto non è un problema per me.

risposta

4

Non sono state aggiunte funzionalità utili solo a un'applicazione o contesto specifici, l'estensione è chiaramente denominata e il comportamento è evidente senza dover considerare l'implementazione.

La risposta è: "Sì, si tratta di"

1

Mi sembra buono, anche se sembra un po 'non convenzionale.

1

Sembra abbastanza giusto, ma farei un passo indietro. Puoi inserire un significato commerciale nel confronto? Quali sono quei valori? Forse staresti meglio con un metodo chiamato IsSpecialCustomerLocation o qualcosa che esprima l'intento reale del codice.

+0

grazie. È abbastanza generico. Stavo solo confrontando un valore enum - era correlato alla programmazione della GUI quindi non aveva alcun significato commerciale in quanto tale. –

1

È inoltre possibile utilizzare il metodo della sintassi LINQ per quell'attività (utilizzando namespace System.Linq):

  object[] objects = new object[10]; 
     objects.Contains(new MyClass()); 

Hmm Fammi pensare un momento ... Oh già utilizzarlo. Ma lo hai messo in un metodo separato invece di chiamarlo direttamente.

+0

È troppo lavoro da fare ogni volta. –

+0

la sintassi dell'inizializzatore dell'array sarebbe ancora più pulita ... vedi il mio post. –

+0

Hai ragione. Essere d'accordo! – Alexander

5

E 'inusuale di scrivere un metodo di estensione per un senza restrizioni T. Non ultimo, questo approccio renderà rapidamente difficile l'utilizzo della vostra intelligenza.

Mentre valida, probabilmente sarei evitare questo come un metodo di estensione - forse basta usare un metodo di utilità statica standard.

La sintassi dell'inizializzatore dell'array C# 3 potrebbe essere più semplice?

bool isTrue = new[] { 1, 2, 3 }.Contains(3); 

Naturalmente, per grandi insiemi di dati, si potrebbe desiderare di memorizzare nella cache una HashSet<T> qualche ;-p

+0

grazie per il commento Marc. potresti spiegare perché questo renderà l'intellisense difficile da usare? –

+0

Perché apparirà su ogni singola variabile quando si preme ".". Ci vuole solo una manciata di questi metodi per iniziare a rendere difficile trovare i metodi rilevanti per un tipo ... in realtà, non vorrai usare questo metodo ** che ** spesso (spero) rispetto a ogni altro metodo disponibile. –

+0

Vedo - buon punto. Grazie. –

1

vorrei fare una classe statica a tale scopo.Questa soluzione non mi piace perché aggiunge un metodo a tutte le classi che sembra un po 'eccessivo. Comunque, in un certo senso, lo fa con OOD perché chiedi agli oggetti di eseguire funzioni su se stessi (kinda).

Tuttavia, vorrei andare con una classe riutilizzabile, invece, perché posso vedere come si potrebbe formare un antipattern. Non lo chiamo ancora un antipattern, ma se troppi di questi costrutti si aprissero potrei chiamarlo un antipattern di leggibilità poiché ogni oggetto sarebbe ingombra di metodi di estensione. Lo considero come inquinamento da spazio dei nomi, ma inquinamento da membro di classe.

if (ConditionHelper.IsEqualToAny(value, value1, value2, value3)) 
{ 
    // Do something 
} 

fa lo stesso lavoro e non inquina nulla.

+0

Venendo a pensarci, soffre di un piccolo problema di leggibilità.Ha a che fare con questo non è ovvio che il valore sia verificato rispetto a value1, value2, value3 e così via. value.IsEqualToAny (value1, value2, value3) ha una migliore leggibilità. La mia preoccupazione riguardava solo i membri inquinanti. – Statement

1

Hai intenzione di fare Contiene e garantire che applichi Contiene su tutti gli oggetti possibili dove potresti utilizzare questo metodo di estensione?

Se alcuni oggetti dati verificano l'uguaglianza sovraccaricando l'operatore ==, la soluzione generica fallirà. Questo non lo rende un vero equivalente dei multipli == test. È anche un buon esempio del pericolo di scrivere metodi di estensione!

Il seguente codice Linq funziona quando si implementa l'overloading dell'operatore e se si utilizza il valore predefinito == di confronto dei riferimenti oggetto, per dire che il valore è in realtà lo stesso oggetto di value1, 2, 3 o 4, dato V come il tipo di oggetto dei vostri valori in questo caso particolare:

V[] lv = { value, value2, value3, value4 }; 
if (lv.Any(v => v==value)) 
    // do something 

o una versione breve mano:

if (new List<V>{value, value2, value3, value4 }.Any(v => v==value)) 
    // do something 

non ho potuto ottenere le espressioni lambda sopra per lavorare in un metodo di estensione generica .

Da buon (se irrilevante) esempio di quello che penso è una bella, la sintassi leggibile, l'idioma in Python sarebbe

if value in (value1, value2, value3, value4): 
+0

Non vedo come questo sia un problema. Il metodo Contains (che è un ExtensionMethod (implementato in System.Linq.Enumerable)) utilizza un EqualityComparer che (nel caso predefinito) utilizza un confronto ==. –

+0

Forse l'ho implementato in modo errato o c'è qualcosa nel modo in cui è legato, ma quando lo provo il metodo di estensione non riesce a rilevare un oggetto che è un oggetto diverso ma uguale in base al suo operatore == sovraccarico. –

0

Se sei solo controllando un valore Enum (come hai detto nel commentare la risposta di Rogers), si dovrebbe usare un FlagsAttribute sull'Enum.

[Flags] 
public enum Value 
{ 
    Value1 = 0, 
    Value2 = 1, 
    Value3 = 2, 
    Value4 = 4 
} 

Value value = Value.Value1; 
if (value | Value.Value1 | Value.Value2 | Value.Value3 | Value.Value4) 
{ 
    // You can also use other bitwise operations, like & (AND),^(XOR) and ~ (NOT) 
} 

Altrimenti; se è specifico del dominio, aggiungilo alla tua logica aziendale. Se è generico, crea una classe helper.

+0

Non penso che sarebbe appropriato. Solo perché voglio verificare un numero di valori diversi non significa che l'enum debba essere un campo di bit. Non voglio che il valore enum sia un valore combinato. - Grazie per la tua indicazione, comunque. Ho usato questo metodo di estensione per un po 'di tempo ed è stato abbastanza utile in un certo numero di situazioni. –