处理一系列相同类型的命名变量

时间:2009-07-08 13:10:08

标签: c#

以下示例很糟糕,因为它有代码重复。例如,如果我们稍后在喝酒之前需要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。不是特别漂亮,但是对于两个以上的人或者饮酒程序足够长时间(品尝葡萄酒)非常值得。(/ p>

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#技巧可以让我非常干净和紧凑地做到这一点?匿名类型?什么?

4 个答案:

答案 0 :(得分: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);
        }
}

答案 1 :(得分: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子句可能对此有所帮助。

答案 2 :(得分:0)

我不知道你对你的类有多少控制,但我会创建一个名为IInjestible(或其他东西)的接口(或使用基类,具体取决于具体需要),然后给每个家伙一个列表(类型IInjestible的列表&lt;&gt;,IEnumerable&lt;&gt;,等等。然后你可以做类似的事情:

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

或者,使用基类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);}
  }
}

答案 3 :(得分:0)

好吧,似乎可以通过改变应用程序的设计来解决这个问题,假设这是可以完成的事情。您可以做的是创建如下界面:

interface IConsumable{ };

然后,您可以让每个耗材类实现此接口,因此您将拥有:

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

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

然后在你的KeyValuePair中你可以发送一个Dude和一组这样的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 }
    }
}

这可能不是最好的设计,但它是向前迈出的一步。如果代码不能按照书面形式工作,我很抱歉,但我很着急。

希望这有帮助。