2009-07-08 75 views
0

以下示例很糟糕,因爲它有代碼重複。例如,如果我們以後需要在喝酒之前CheckExpirationDate,我們需要在多個地方添加函數調用。如果我們需要將charleystan添加到派對上,代碼會變得很快。處理一系列相同類型的命名變量

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

解決方案可能是構建這些對象的數組。如果您需要一次操作一個對象,這非常簡單。例如,如果每個人都在身邊掠過的啤酒單瓶:

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

要改寫原來的例子,我們可以使用一個KeyValuePair。不是特別漂亮,但是對於兩個以上的男士或者如果飲用程序足夠長(品酒),這是非常值得的。

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

但是,如果我們一次需要操作三個或更多的對象呢?例如,約翰飲料啤酒吃玉米片。我們可以求助於聲明自定義類型,但這會使得代碼依賴於遠處的其他代碼。我們可以將每種類型放在它自己的數組中,並執行一個好的舊的for循環並訪問帶索引的對象,但這意味着要創建命名數組(Dude[] dudes = new Dude { john, bob };)。

我在問的是是否有一些奇特的C#技巧可以讓我乾淨而緊湊地做到這一點?匿名類型?什麼東西?

+0

您的第一個和第三個代碼示例並不相同,正如您所說的那樣。在第三個樣品中,鮑勃從不喝他的蘋果酒...... – LBushkin 2009-07-08 13:17:40

+0

請詳細說明。 – CannibalSmith 2009-07-10 12:09:04

回答

2

你提到的匿名類型,這應該做的伎倆:

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

那麼....假設你有三個不同的Dudes,Boozes和Foods的集合,你可以使用LINQ查詢並創建一個匿名類型。那麼你不必擔心創建一個新類型和可能由它創建的任何依賴關係。這裏有一個例子:

// 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); 
    } 
} 

缺點:

  • 匿名類型必須從調用塊中使用 - 你不能從方法返回匿名類型。
  • 您需要預先存在的集合。
  • 列出的代碼爲每個傢伙,食物和酒水選項創建配對。你可能實際上並不需要這個。然而,where子句可能有幫助。
+0

爲什麼不直接在頂部查詢中添加「where!dude.IsDesignatedDriver」? – 2009-07-08 13:23:09

0

我不知道你有多大的控制了自己的類,但我會創造一個接口(或使用一個基類,根據具體需要)調用IInjestible(或某物),然後給每個傢伙一個列表(列表<>,IEnumerable <>,無論)IInjestible類型。然後,你可以這樣做:

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

或者,用一個基類小吃:

 
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

那麼它似乎這是有可能通過改變應用程序的假設,將設計固定是可以做的事情。你可以做的就是創建一個類似如下的界面:

interface IConsumable{ }; 

然後你可以有你的消耗品類的每一個實現這個接口,所以你會:

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

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

然後可以發送一個花花公子和IConsumable對象這樣

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

這可能不是最好的設計數組,但它是向前邁進了一步。我很抱歉,如果代碼不能像書面形式工作,但我很匆忙。

希望這會有所幫助。

相關問題