是否可以将Func <bool>作为while条件</bool>

时间:2011-12-16 16:52:37

标签: c# loops lambda

晚上好,

我想知道我是否可以做类似的事情:

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

但是我没有使用while(true)循环,而是希望将条件逻辑封装在Func中并像这样执行它:

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

至少在我的情况下,它会看起来更干净,但我不知道该怎么做(在Func / Action中有点新的。)。

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

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

但那是对数据库的2次调用......

谢谢=)

4 个答案:

答案 0 :(得分:4)

可以拥有:

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可以使它稍微不那么可怕,但它仍然不好。)

答案 1 :(得分:2)

你可以这样做,但如果你没有令人信服的理由这样做(比如你将条件函数作为参数传递),我只需将你的逻辑包装在一个函数中并直接调用它:

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

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

答案 2 :(得分:0)

首先,在while循环中进行数据库调用是一个坏主意。事先查询您需要的内容并相应地循环。

出现多态性可以成为你的朋友。如果你需要保持相同的流程,你可以这样做:

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

然后你可以在这个可枚举的地方使用TakeWhile

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

所有这一切,您只需查询您想要的内容并开展工作。

答案 3 :(得分:0)

嗯,首先你不能&#34;新&#34;一个Func,就像你可以修改任何代表类型一样。您必须改为分配现有的命名方法或函数文字(也称为匿名委托,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#中做你想做的事情;必须将匿名委托分配给变量或参数才能使用。它不能作为一个&#34;函数文字就地使用&#34;在抽象意义上。

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