以下示例很糟糕,因为它有代码重复。例如,如果我们稍后在喝酒之前需要CheckExpirationDate
,我们需要在多个地方添加函数调用。如果我们需要将charley
和stan
添加到聚会中,则代码会很快变大。
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#技巧可以让我非常干净和紧凑地做到这一点?匿名类型?什么?
答案 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);
}
}
缺点:
答案 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 }
}
}
这可能不是最好的设计,但它是向前迈出的一步。如果代码不能按照书面形式工作,我很抱歉,但我很着急。
希望这有帮助。