2009-02-11 27 views
10

Ich schrieb nur eine if-Anweisung in den Zeilen derIst dies eine gute Anwendung eines ExtensionMethod?

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

und es ärgert mich, dass ich den ‚Wert ==‘ wiederholen müssen immer Teil. Meiner Meinung nach dient dies keinem anderen Zweck, als das Lesen zu erschweren.

Ich schrieb die folgende Extension der oben beschriebenes Szenario besser lesbar machen sollte:

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

Jetzt kann ich einfach schreiben

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

Ist das eine gute Verwendung einer Extension?

EDIT:

Vielen Dank für die tollen Antworten. Zur Erinnerung: Ich habe die Methode beibehalten. Während der Vorschlag, dass man einfach new []{value1,value2,value3,value4}.Contains(value) wahr ist, verwenden könnte, ziehe ich einfach diese Art von if-Anweisung Lesen von links nach rechts (, wenn dieser Wert auf eine dieser statt gleich diesen Wert, wenn diese Werte enthalten). Es ist für mich kein Problem mehr eine Methode in intellisense auf jedem Objekt zu zeigen.

Antwort

4

Sie haben keine Funktionen hinzugefügt, die nur für eine bestimmte Anwendung oder einen bestimmten Kontext nützlich sind, Ihre Erweiterung ist eindeutig benannt und das Verhalten ist offensichtlich, ohne dass Sie sich die Implementierung ansehen müssen.

Die Antwort ist „Ja, es ist“

1

Sieht gut aus, obwohl es ein wenig unkonventionell scheint.

1

Es scheint ziemlich fair, aber ich würde einen Schritt zurücktreten. Können Sie dem Vergleich eine geschäftliche Bedeutung zuordnen? Was sind diese Werte? Vielleicht wärst du besser dran mit einer Methode namens IsSpecialCustomerLocation oder etwas, das die eigentliche Absicht des Codes ausdrückt.

+0

danke. Es ist ziemlich generisch. Ich habe gerade einen Enum-Wert verglichen - er war mit der GUI-Programmierung verwandt, also hatte er keine geschäftliche Bedeutung. –

1

Sie können auch LINQ Methode Syntax für diese Aufgabe verwenden (durch System.Linq Namespace):

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

Hmm lassen Sie mich einen Moment denken ... Oh Sie mit ihr schon. Aber Sie haben es in eine separate Methode eingefügt, anstatt es direkt aufzurufen.

+0

Das ist viel zu viel Arbeit jedes Mal zu tun. –

+0

die Array-Initialisierer-Syntax wäre noch sauberer ... siehe meinen Beitrag. –

+0

Sie haben Recht. Zustimmen! – Alexander

5

Es ist ungewöhnlich, eine Erweiterungsmethode für einen unbeschränkten T zu schreiben. Nicht zuletzt wird dieser Ansatz Ihr Intellisense-Programm schnell in Schwierigkeiten bringen.

Während gültig, würde ich wahrscheinlich diese als eine Erweiterungsmethode vermeiden - vielleicht verwenden Sie einfach eine standardmäßige Standard-Dienstprogramm-Methode.

Die C# 3-Array-Initialisierersyntax könnte einfacher sein?

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

Natürlich, für große Datenmengen, könnte man ein HashSet<T> irgendwo ;-p

+0

danke für den Kommentar Marc. Können Sie erklären, warum dies die Verwendung von Intellisense erschwert? –

+0

Weil es auf jeder einzelnen Variable erscheint, wenn Sie "." Drücken. Es braucht nur eine Handvoll solcher Methoden, um zu beginnen, die für einen Typ relevanten Methoden schwer zu finden ... in Wirklichkeit werden Sie diese Methode nicht ** gerne ** verwenden, (oft im Vergleich zu) jede andere verfügbare Methode. –

+0

Ich sehe - guter Punkt. Vielen Dank. –

1

Ich würde eine statische Klasse machen zu diesem Zweck gecached werden soll.Ich mag diese Lösung nicht, weil sie allen Klassen eine Methode hinzufügt, die etwas übertrieben erscheint. Allerdings geht es in gewisser Weise mit OOD, weil Sie die Objekte bitten, Funktionen an sich selbst (irgendwie) auszuführen.

Trotzdem würde ich stattdessen mit einer wiederverwendbaren Klasse gehen, weil ich sehen kann, wie sich ein Antipattern bilden könnte. Ich nenne es noch kein Antipattern, aber wenn zu viele dieser Konstrukte auftauchen, würde ich das als Antipattern der Lesbarkeit bezeichnen, da jedes Objekt mit Erweiterungsmethoden überladen würde. Ich sehe es wie Namespace Verschmutzung, aber Klassenmitglied Verschmutzung.

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

Hat die gleiche Arbeit und verschmutzt nichts.

+0

Wenn ich darüber nachdenke, leidet es an einem kleinen Lesbarkeitsproblem.Es hat damit zu tun, dass es nicht offensichtlich ist, dass Wert gegen value1, value2, value3 usw. geprüft wird. value.IsEqualToAny (value1, value2, value3) hat eine bessere Lesbarkeit. Meine Sorge galt nur den verschmutzenden Mitgliedern. – Statement

1

Sind Sie wirklich beabsichtigen, zu tun und garantieren, dass Sie auf alle möglichen Objekte anwenden anwenden, wo Sie diese Erweiterungsmethode verwenden könnten?

Wenn einige gegebene Objekte Gleichheit durch Überladen von Operator == testen, wird Ihre generische Lösung fehlschlagen. Das ist kein echtes Äquivalent zu den multiple == Tests. Es ist auch ein gutes Beispiel für die Gefahr, Erweiterungsmethoden zu schreiben!

Der folgende Linq-Code funktioniert, wenn Sie Operatorüberladung implementieren, sowie wenn Sie die Standard == Bedeutung des Vergleichs von Objektreferenzen verwenden, um zu sagen, dass Wert tatsächlich das gleiche Objekt wie Wert1, 2, 3 oder 4 ist V als Objekttyp Ihrer Werte in diesem speziellen Fall:

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

Oder eine kurze Hand Version:

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

ich nicht die oben genannte Lambda-Ausdrücke bekommen konnte in einer allgemeinen Erweiterungsmethode arbeiten .

Als gut (wenn nicht relevant) Beispiel dafür, was ich denke, eine schöne, gut lesbare Syntax ist, würde das Idiom in Python

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

Ich sehe nicht, wie das ein Problem ist. Die Contains-Methode (die ein ExtensionMethod ist (implementiert in System.Linq.Enumerable)) verwendet einen EqualityComparer, der (im Standardfall) einen == -Vergleich verwendet. –

+0

Vielleicht habe ich es falsch implementiert oder es gibt etwas über die Art, wie es gebunden ist, aber wenn ich es teste, kann die Erweiterungsmethode ein Objekt nicht erkennen, das ein anderes Objekt ist, aber basierend auf seinem Operator == überladen. –

0

sein, wenn Sie nur einen Enum-Wert werden überprüft (wie Sie in dem genannten Kommentar zu Rogers Antwort), sollten Sie eine FlagsAttribute auf der Enum verwenden.

[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) 
} 

Sonst; Wenn es domänenspezifisch ist, fügen Sie es Ihrer Geschäftslogik hinzu. Wenn es generisch ist, erstellen Sie eine Hilfsklasse.

+0

Ich denke nicht, dass das angemessen wäre. Nur weil ich nach verschiedenen Werten suchen möchte, heißt das nicht, dass die Enum ein kleines Feld sein sollte. Ich möchte nicht, dass der Enum-Wert ein kombinierter Wert ist. - Danke für Ihre Eingabe. Ich verwende diese Erweiterungsmethode schon seit einiger Zeit und es war in einer Reihe von Situationen sehr nützlich. –

Verwandte Themen