2009-07-08 14 views
0

Das folgende Beispiel ist schlecht, da es Codewiederholung hat. Zum Beispiel, wenn wir später CheckExpirationDate vor dem Trinken brauchen, müssen wir den Funktionsaufruf an mehreren Stellen hinzufügen. Wenn wir charley und zu der Party hinzufügen müssen, wird der Code sehr schnell.Behandeln einer Reihe von benannten Variablen des gleichen Typs

if (john != designatedDriver) 
{ 
    beer.Open(); 
    john.Drink(beer); 
} 
if (bob != designatedDriver) 
{ 
    cider.Open(); 
    bob.Drink(cider); 
} 

Die Lösung könnte sein, ein Array dieser Objekte zu erstellen. Das ist sehr einfach, wenn Sie ein Objekt gleichzeitig bedienen müssen. Zum Beispiel ist vorbei, wenn jeder um eine einzige Flasche Bier:

beer.Open(); 
foreach (Dude i in new Dude[] { john, bob }) 
{ 
    i.Drink(beer); 
} 

das ursprüngliche Beispiel zu umschreiben, wir KeyValuePair verwenden können. Nicht besonders schön, aber es lohnt sich für mehr als zwei Jungs oder wenn der Trinkvorgang lang genug ist (Weinprobe).

foreach (KeyValuePair<Dude, Booze> i in KeyValuePair<Dude, Booze>[] { 
    new KeyValuePair<Dude, Booze>(john, beer), 
    new KeyValuePair<Dude, Booze>(bob, cider) }) 
{ 
    if (i.Key != designatedDriver) 
    { 
     i.Value.Open(); 
     i.Key.Drink(i.Value); 
    } 
} 

Aber was, wenn wir zu einer Zeit, drei oder mehr Objekte in Betrieb nehmen müssen? Zum Beispiel John Getränke Bier und isst Nachos. Wir können darauf zurückgreifen, benutzerdefinierte Typen zu deklarieren, aber das würde den Code von irgendwo weit entferntem Code abhängig machen. Wir könnten jeden Typ in ein eigenes Array setzen und eine gute alte for-Schleife ausführen und auf die Objekte mit Indizes zugreifen, aber das würde bedeuten, benannte Arrays zu erzeugen (Dude[] dudes = new Dude { john, bob };).

Was ich frage ist, gibt es einige ausgefallene C# Trick, die mich das sehr sauber und kompakt machen würde? Anonyme Typen? Etwas?

+0

Ihr erstes und drittes Codebeispiel sind nicht gleichwertig, wie Sie sagen. In der dritten Probe trinkt Bob nie seinen Apfelwein ... – LBushkin

+0

Aufwendig, bitte. – CannibalSmith

Antwort

2

Sie haben erwähnt, anonyme Typen, sollte dies den Trick:

foreach (var i in new[] { 
          new{Dude=john, Booze=beer, Food=nachos}, 
          new{Dude=bob, Booze=cider, Food=chips} 
         }) 
{ 
     if (i.Dude != designatedDriver) 
     { 
       i.Booze.Open(); 
       i.Dude.Drink(i.Booze); 
       i.Dude.Eat(i.Food); 
     } 
} 
+0

Der designierte Fahrer darf auch nicht essen? Das ist einfach gemein! – LukeH

+0

Hmmm ... Zum Schutz vor Lebensmittelvergiftung? –

0

Nun .... vorausgesetzt, Sie hatten drei getrennte Sammlungen von Dudes, Boozes und Foods, könnten Sie eine LINQ-Abfrage verwenden und einen anonymen Typ erstellen. Dann müssen Sie sich keine Gedanken darüber machen, einen neuen Typ und Abhängigkeiten zu erstellen, die möglicherweise von diesem erstellt werden. Hier ein Beispiel:

// assumes existing collections called "boozes" "dudes" and "foods" 
var qry = from booze in boozes 
      from dude in dudes 
      from food in foods 
      select new { 
       Dude = dude, 
       Booze = booze, 
       Food = food 
      }; 

foreach(var item in qry) 
{ 
    if(!item.Dude.IsDesignatedDriver) 
    { 
     item.Booze.Open(); 
     item.Food.Cook(); 
     item.Dude.Drink(item.Booze); 
     item.Dude.Eat(item.Food); 
    } 
} 

Die Nachteile:

  • der anonyme Typ muss aus dem rufenden Block verwendet werden - nicht anonyme Typen von einer Methode zurückgeben kann.
  • Sie benötigen bereits vorhandene Sammlungen.
  • Der aufgelistete Code erstellt eine Paarung für jeden Typ, Essen und Alkohol Option. Das mag man eigentlich nicht wollen. Eine WHERE-Klausel kann jedoch dort helfen.
+0

Warum nicht einfach einen "where! Dude.IsDesignatedDriver" zur obersten Abfrage hinzufügen? –

+0

Dies gibt das kartesische Produkt von Typ x trinken x Essen, wenn ich denke, dass Sie sie gezippt haben wollten. Wir fügen der Erweiterungsmethodenbibliothek für die nächste Version des Frameworks einen Zip-Sequenzoperator hinzu. –

0

Ich weiß nicht, wie viel Kontrolle Sie über Ihre Klassen haben, aber ich würde eine Schnittstelle (oder verwenden Sie eine Basisklasse erstellen , je nach den spezifischen Bedürfnissen) als "nicht wahrnehmbar" (oder etwas) bezeichnet, und geben Sie jedem Typen eine Liste (Liste <>, IEnumerable <>, was auch immer) des Typs IInjestible.Dann könnten Sie so etwas wie:

 
foreach (Dude dude in Dudes) 
{ 
    foreach(IInjestible snack in Snacks) 
    { 
    snack.Injest(dude); 
    } 
} 

Oder mit einer Basisklasse Snack:

 
foreach(Dude dude in Dudes) 
{ 
    foreach(Snack snack in Snacks) 
    { 
    if(snack is Drink) {dude.drink(snack);} 
    if(snack is Food) {dude.eat(snack);} 
    } 
} 
0

Nun, es scheint, dass dies etwas ist, das durch eine Änderung der Gestaltung der Anwendung festgelegt werden könnte, dass unter der Annahme, ist etwas, was getan werden kann. Was können Sie tun, ist eine Schnittstelle wie folgt erstellen:

interface IConsumable{ }; 

Dann können Sie diese Schnittstelle die jede Ihrer Verbrauchs Klassen implementieren, so dass Sie haben würde:

class Beer : IConsumable, IDrink { 
    public void Drink { ...; } 
} 

class Nachos : IConsumable, IFood { 
    public void East { ...; } 
} 

Dann in Ihrem KeyValuePair Sie kann Send.weiterl einen Geck und eine Reihe von IConsumable Objekten wie diese

foreach (KeyValuePair<Dude, IConsumable[]> i in KeyValuePair<Dude, IConsumale[]>[] { 
    foreach(IConsumable consumable in i.Value) { 
     if(consumable is IFood){ 
      //Code for food 
     } 
     if(consumable is IDrink){ 
      //Code for drinks 
     } 
     //You can even be more specific 
     if(consumable is Beer){ //Code for Beer } 
    } 
} 

Dies könnte nicht das beste Design, aber es ist ein Schritt. Ich entschuldige mich, wenn der Code nicht wie geschrieben funktioniert, aber ich hatte es eilig.

Hoffe, das hilft.

Verwandte Themen