语法问题 IEnumerable;使用yield返回的方法
这是我的方法:
static IEnumerable<DateTime> GetMonths(DateTime from, DateTime to)
{
// if logs is not uptodate
TimeSpan logsMissingTimespan = to - from;
if (logsMissingTimespan != new TimeSpan(0))
{
return GetMonthsBetweenTwoDates(from, to);
}
return null; // Why this line ?
}
private static IEnumerable<DateTime> GetMonthsBetweenTwoDates(DateTime from, DateTime to)
{
DateTime date = from;
DateTime lastDate = DateTime.MaxValue;
while (date < to)
{
if (lastDate.Month != date.Month)
{
lastDate = date;
yield return lastDate;
}
date = date.AddDays(1);
}
}
它工作正常,但我想我可以写一些更干净的东西,如下所示:
static IEnumerable<DateTime> GetMonths(DateTime from, DateTime to)
{
TimeSpan logsMissingTimespan = to - from;
if (logsMissingTimespan == new TimeSpan(0))
{
yield break;
}
return GetMonthsBetweenTwoDates(from, to);
}
但我有一条错误消息:
无法从迭代器返回值。使用yield return语句返回一个值,或者使用yield break结束迭代。
为什么我应该return null
以及正确的语法是什么?
编辑:
所以,正确的方法是使用 Enumerable.Empty :
static IEnumerable<DateTime> GetMonths(DateTime from, DateTime to)
{
// if logs is not uptodate
TimeSpan logsMissingTimespan = to - from;
if (logsMissingTimespan != new TimeSpan(0))
{
return GetMonthsBetweenTwoDates(from, to);
}
return Enumerable.Empty<DateTime>();
}
Here is my method :
static IEnumerable<DateTime> GetMonths(DateTime from, DateTime to)
{
// if logs is not uptodate
TimeSpan logsMissingTimespan = to - from;
if (logsMissingTimespan != new TimeSpan(0))
{
return GetMonthsBetweenTwoDates(from, to);
}
return null; // Why this line ?
}
private static IEnumerable<DateTime> GetMonthsBetweenTwoDates(DateTime from, DateTime to)
{
DateTime date = from;
DateTime lastDate = DateTime.MaxValue;
while (date < to)
{
if (lastDate.Month != date.Month)
{
lastDate = date;
yield return lastDate;
}
date = date.AddDays(1);
}
}
it works fine but I think I can write something cleaner like this :
static IEnumerable<DateTime> GetMonths(DateTime from, DateTime to)
{
TimeSpan logsMissingTimespan = to - from;
if (logsMissingTimespan == new TimeSpan(0))
{
yield break;
}
return GetMonthsBetweenTwoDates(from, to);
}
But I have an error message :
Cannot return a value from an iterator. Use the yield return statement to return a value, or yield break to end the iteration.
Why should I have a return null
and what is the correct syntax ?
EDIT :
So, the correct way is to use Enumerable.Empty :
static IEnumerable<DateTime> GetMonths(DateTime from, DateTime to)
{
// if logs is not uptodate
TimeSpan logsMissingTimespan = to - from;
if (logsMissingTimespan != new TimeSpan(0))
{
return GetMonthsBetweenTwoDates(from, to);
}
return Enumerable.Empty<DateTime>();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您不需要在第一次检查时使用 Yield Break 来结束迭代。
you don't need yield break to end the iteration at your first check.
因为您使用了
yield
这个词,所以它现在期望该方法一次yield一个元素。每次迭代只能使用yield return
或yield break
返回一个元素。您应该使用
Enumerable.Empty();
而不是yield break
。Because you have used the word
yield
it now expects the method to yield one element at a time. It must only useyeild return
oryield break
to return one element per iteration.You should use
Enumerable.Empty<DateTime>();
instead ofyield break
.前两个示例的形式会产生不同类型的输出。
如果满足条件,您的第一个示例将直接返回
IEnumerable
,如果不满足,则返回 null 引用。您的第二个示例始终返回一个IEnumerable
,但条件确定它是否包含任何元素。第二个示例是通过使用迭代器块来完成的。 C# 编译器使用
yield
语法将您编写的函数转换为实现IEnumerable
的自定义(隐藏)类型和实现的类型>IEnumerator
。这些类型实现必要的状态机,以实现(希望)您放入函数中的逻辑。正因为如此,你不能混合范例;您必须从函数返回IEnumerable
实例(并且根本不使用yield
),或者所有内容都必须通过yield
返回代码>.如果您只关心返回 null 引用这一事实,则可以通过返回
Enumerable.Empty
而不是null
来使这些方法在语义上相同代码>.The forms of your first two examples produce different sorts of output.
Your first example returns an
IEnumerable<T>
directly if the condition is satisfied, and a null reference if it is not. Your second example always returns anIEnumerable<T>
, but the condition determines whether or not it has any elements.The second example is done by using an iterator block. The
yield
syntax is used by the C# compiler to turn the function that you wrote into a custom (hidden) type that implementsIEnumerable<T>
and a type that implementsIEnumerator<T>
. These types implement the necessary state machines in order to achieve (hopefully) the logic that you've placed into the function. Because of this, you cannot mix paradigms; you must either return an instance ofIEnumerable<T>
from the function (and not useyield
anywhere at all), or everything must be returned viayield
.If all you're concerned with is the fact that you're returning a null reference, you could make the methods semantically the same by returning
Enumerable.Empty<DateTime>
rather thannull
.方法要么是用迭代器块实现的,要么不是——所以要么一切都以
yield return
和yield break
表示,要么都没有这是。但是,您不需要做任何特别的事情。您原来的
GetMonthsBetweenTwoDates
已经可以在to == from
处工作,因为它永远不会进入 while 循环。另一方面,您对
lastDate
的使用对我来说看起来很可疑 - 特别是,如果from
碰巧在同一个月,它看起来会做不同的事情DateTime.MaxValue
。A method is either implemented with an iterator block or it's not - so either everything is in terms of
yield return
andyield break
, or none of it is.However, you don't need to do anything special. Your original
GetMonthsBetweenTwoDates
already works whereto == from
, because it'll never enter the while loop.On the other hand, your use of
lastDate
looks suspicious to me - in particular, it looks like it'll do something different iffrom
happens to be in the same month asDateTime.MaxValue
.