C# 在迭代器中作为返回的自定义类

C# 在迭代器中作为返回的自定义类,c#,C#,我有一个扩展方法,它使用DateTimes遍历POCO类的列表。然后,此方法将重叠或落在彼此的公差时间跨度内的明细表组合在一起。这个很好用 然而,我需要的一部分是获得一个组合项目的ID列表(来自DB),以供以后参考。我试图转换扩展方法以返回自定义类,但出现以下错误: Error CS1624 The body of 'Extensions.Combine(CombinedSchedules)' cannot be an iterator block because 'CombinedSch

我有一个扩展方法,它使用DateTimes遍历POCO类的列表。然后,此方法将重叠或落在彼此的公差时间跨度内的明细表组合在一起。这个很好用

然而,我需要的一部分是获得一个组合项目的ID列表(来自DB),以供以后参考。我试图转换扩展方法以返回自定义类,但出现以下错误:

Error   CS1624  The body of 'Extensions.Combine(CombinedSchedules)' cannot be an iterator block because 'CombinedSchedules' is not an iterator interface type
以下是我的扩展方法:

        public static CombinedSchedules Combine(this CombinedSchedules items)
    {
        using (IEnumerator<ScheduleDto> enumerator = items.Schedules.GetEnumerator())
        {
            if (!enumerator.MoveNext())
            {
                yield break;
            }

            var previous = enumerator.Current;
            while (enumerator.MoveNext())
            {
                var next = enumerator.Current;

                if (TryCombine(previous, next, out var combined))
                {
                    items.IncludedSchedules.TryAdd(previous.Id);
                    previous = combined;
                    continue;
                }

                yield return previous;
                previous = next;

            }

            yield return previous;
        }
    }
公共静态组合计划合并(此组合计划项目)
{
使用(IEnumerator枚举器=items.Schedules.GetEnumerator())
{
如果(!enumerator.MoveNext())
{
屈服断裂;
}
var previous=枚举数。当前值;
while(枚举数.MoveNext())
{
var next=枚举数.Current;
if(TryCombine(上一个、下一个、外var组合))
{
项目.包括附表.TryAdd(先前的.Id);
先前=合并;
持续
}
以前的收益率;
上一个=下一个;
}
以前的收益率;
}
}
以下是CombinedSchedules类:

public class CombinedSchedules : IEnumerable<ScheduleDto>, IDisposable
{
    bool disposed = false;
    // Instantiate a SafeHandle instance.
    SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true);

    public List<ScheduleDto> Schedules { get; set; }
    public List<int> IncludedSchedules { get; set; }



    public IEnumerator GetEnumerator()
    {
        return Schedules.GetEnumerator();
    }

    IEnumerator<ScheduleDto> IEnumerable<ScheduleDto>.GetEnumerator()
    {
        return Schedules.GetEnumerator();
    }

    #region IDisposable Support
    private bool disposedValue = false; // To detect redundant calls

    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                // TODO: dispose managed state (managed objects).
            }

            // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
            // TODO: set large fields to null.

            disposedValue = true;
        }
    }

    // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
    // ~CombinedSchedules() {
    //   // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
    //   Dispose(false);
    // }

    // This code added to correctly implement the disposable pattern.
    public void Dispose()
    {
        // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
        Dispose(true);
        // TODO: uncomment the following line if the finalizer is overridden above.
        // GC.SuppressFinalize(this);
    }
    #endregion
}
公共类组合计划:IEnumerable,IDisposable
{
布尔=假;
//实例化一个SafeHandle实例。
SafeHandle=新的SafeFileHandle(IntPtr.Zero,true);
公共列表计划{get;set;}
公共列表IncludedSchedules{get;set;}
公共IEnumerator GetEnumerator()
{
返回Schedules.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
返回Schedules.GetEnumerator();
}
#区域IDisposable支持
private bool disposedValue=false;//用于检测冗余调用
受保护的虚拟void Dispose(bool disposing)
{
如果(!disposedValue)
{
如果(处置)
{
//TODO:处置托管状态(托管对象)。
}
//TODO:释放非托管资源(非托管对象)并覆盖下面的终结器。
//TODO:将大字段设置为null。
disposedValue=true;
}
}
//TODO:仅当上面的Dispose(bool disposing)具有释放非托管资源的代码时,才重写终结器。
//~CombinedSchedules(){
////不要更改此代码。请将清理代码放入上面的Dispose(bool disposing)中。
//处置(虚假);
// }
//添加此代码是为了正确实现一次性模式。
公共空间处置()
{
//不要更改此代码。请将清理代码放入上面的Dispose(bool disposing)中。
处置(真实);
//TODO:如果上面覆盖了终结器,则取消对以下行的注释。
//总干事(本);
}
#端区
}

我怎样才能取回所有我需要的东西,以便以后参考组合时间表列表?提前谢谢

如果
Combine
方法应该返回一个新的
CombinedSchedules
对象,我建议将其从迭代器方法转换为“普通”扩展方法,大致遵循以下逻辑:


扩展方法将枚举并组合来自提供的原始源CombinedSchedules对象的ScheduleDto实例,并在此过程中构建一个新的IncludedSchedules集合。使用合并的ScheduleDto和新的IncludedSchedules集合,将创建并返回一个新的CombinedSchedules对象。

在方法中使用
收益返回
收益中断
时,它必须返回
IEnumerable
IEnumerator
或通用版本。这里发生的是C编译器将您的方法重建为实现
IEnumerator
IEnumerable
的对象的
MoveNext
方法

编译器不知道如何构建列表、字典、字符串或任何其他也实现了
IEnumerable
的类型

现在,您想要的特性是可能的,我们知道这是可能的,因为C#7对
async
方法是这样做的。在以前的版本中,
async
方法只能返回
Task
void
Task
,原因与此相同,但在C#7中,编译器团队添加了提供您自己的“任务生成器”类的功能

理论上,编译器团队可以对迭代器块做同样的事情,但总体感觉对该功能的需求不大

那么,您最好选择以下两种策略之一:

  • 坚持使用生成的方法,然后编写另一个扩展方法,将序列转换为数据类型。请参阅
    ToList
    ,或
    ToDictionary
    string.Join
    或任何其他方法,这些方法采用一个序列并返回从该序列派生的完全不同的数据结构。如果经常需要从序列构造摘要对象,则此技术非常有用。调用站点将是
    combined.GetSchedules().Combine()
    其中
    GetSchedules()
    接受
    CombinedSchedule
    并返回
    IEnumerable
    Combine()
    接受
    IEnumerable
    并返回
    CombinedSchedule
  • 停止屈服;创建一个CombinedScheduleBuilder对象,并在生成的任何地方调用生成器上的Add方法。(屈服断裂变为返回。)方法所做的最后一件事是返回构建器构建的内容。这对于简单地将一个对象转换为另一个对象的情况非常有用,这似乎很适合您的场景。(这基本上是elgonzo的答案提出的想法。)

您的枚举器似乎正在使用