2011-12-16 50 views
0

晚上好,是否有可能有一个Func键<bool>作为while条件

我在想,如果我可以这样做:

while(true) 
{ 
    MyEnum currentValue = GetMyEnumValueFromDB(); 
    if(currentValue == MyEnum.BreakIfYouGetThis) 
     break; 
    else if(currentValue == MyEnum.AlsoBreakIfYouGetThis) 
     break; 
    else 
     //Do some computing 
} 

而不是有一段时间(true)循环但是,我想封装在一个函数功能条件逻辑并执行这样的:

while(new Func<bool>(/* what goes here? */)) 
{ 
    //Do some computing 
} 

在我的情况下,至少,它看起来干净多了,但我不知道如何做到这一点(还挺新在乐趣C /动作..)。

编辑希望这个澄清:
它也可以做这样的:

while(GetMyEnumValueFromDB() != MyEnum.BreakIfYouGetThis && 
     GetMyEnumValueFromDB() != MyEnum.AlsoBreakIfYouGetThis) 
{ 
    //Do some computing 
} 

但是,这2调用数据库...

感谢=)

回答

3

好你可以

Func<bool> condition = ...; 

while (condition()) 
{ 
} 

是你在想什么?这不是真的清楚......

编辑:在这个例子中,你已经给了,我会使用类似:

private static readonly MyEnum[] BreakEnumValues = { 
    MyEnum.BreakIfYouGetThis, 
    MyEnum.AlsoBreakIfYouGetThis 
}; 

... 

while (!BreakEnumValues.Contains(GetMyEnumValueFromDB())) 
{ 
    ... 
} 

或者:

private static bool ShouldBreak(MyEnum enumFromDatabase) 
{ 
    return enumFromDatabase == MyEnum.BreakIfYouGetThis || 
      enumFromDatabase == MyEnum.AlsoBreakIfYouGetThis; 
} 

... 

while (!ShouldBreak(GetMyEnumValueFromDB)) 
{ 
    ... 
} 

编辑:为了对抗KeithS的答案,这是完全正确的:

while (new Func<bool>(() => { 
    Console.WriteLine("Evaluating..."); 
    return true; 
})()) { 
    Console.WriteLine("In loop"); 
    count++; 
    if (count == 5) 
    { 
     break; 
    } 
} 

这是可怕的,但它是有效的。 (通过明确地调用Invoke可以使它变得更轻微,但它仍然不是很好)。

+0

我想把整个Func 的创建和计算用括号括起来。 – 2011-12-16 16:56:43

+1

@Baboon:为什么?这将在每次迭代中创建一个新的委托 - 我看不到仅仅在没有*的情况下使用委托会带来什么好处。你*声称*有些东西看起来更干净,但它完全不清楚为什么。 – 2011-12-16 16:58:44

+0

我喜欢这个答案,但我也会质疑为什么狒狒需要创建一个Func来表示他的状况。如果在本地范围内,Func中的表达式可以直接进行评估。在这种情况下,Func的主要用途是轻松地将它们交换出来,在这种情况下,您需要变量,以便您可以更改分配给它的委托。 – KeithS 2011-12-16 17:03:34

2

你可以这样做,但如果你没有一个令人信服的理由这样做(就像你通过条件功能作为参数),我只是换你的逻辑在一个函数,直接调用它:

while(KeepGoing()) 
{ 
    //Do stuff 
} 

bool KeepGoing() 
{ 
    // Check conditions for continuing 
    var value = GetMyEnumValueFromDB(); 
    return value != MyEnum.BreakIfYouGetThis && value != MyEnum.AlsoBreakIfYouGetThis; 
} 
0

首先,在一个while循环数据库调用是一个坏主意。查询你需要什么,并相应地循环。

似乎该多态性可以是你的朋友在这里。如果你需要保持同样的流量,你可以做这样的事情:

foreach(var item in queriedAsIWhileLoopContinuable.TakeWhile(c => c.KeepGoing)) 
{ 
    item.DoWork(); 
} 

之所以这么说,你可以只查询:

interface IWhileLoopContinuable 
{ 
    bool KeepGoing {get;} 
    void DoWork(); 
} 

然后你可以在此枚举使用TakeWhile你想要什么以及如何工作。

0

嗯,首先你不能“新”函数求,就像你不能将新的任何委托类型。您必须改为分配一个现有的已命名方法或函数文字(又名匿名代理,lambda等)来初始化一个Func变量。

//these won't compile; Func has no constructor 
Func<bool> condition = new Func<bool>(); 

//As Jon Skeet notes, these will compile because of language-provided syntax, 
//even though Funcs have no constructor with a delegate parameter. 
Func<bool> condition = new Func<bool>(SomeNamedMethodReturnsBool); 
Func<bool> condition = new Func<bool>(()=>true); 

//and these will compile because you're directly assigning the delegate 
Func<bool> condition = SomeNamedMethodReturnsBool; 
Func<bool> condition =()=>true; 

你实际上不能在C#中做你想做的事情;必须将匿名委托分配给变量或参数才能使用。在抽象意义上,它不能作为“函数文字”就地使用。

即使你可以,这样的声明的效用逃脱我。委托不会每次都被重新实例化(编译器将匿名委托转化为包含类的命名私有函数,并使用混搭名称),但是您要在调用堆栈上添加一个图层,以便评估可能存在的常量表达式直接放置在while()语句的括号中。匿名委托的主要用途是你可以在运行时交换lambda表达式,为了做到这一点,你必须有一个变量。

相关问题