2009-07-08 74 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 } 
    } 
} 

这可能不是最好的设计数组,但它是向前迈进了一步。我很抱歉,如果代码不能像书面形式工作,但我很匆忙。

希望这会有所帮助。

相关问题