【问题标题】:Yield keyword giving unexpected values for IEnumerableYield 关键字为 IEnumerable 提供了意外的值
【发布时间】:2020-05-24 00:56:08
【问题描述】:

这是我的代码(扩展方法)

public static IEnumerable<uint> GetFieldVals(this DataSource rs, IEnumerable<string> columnNames, Predicate<uint> shouldRun)
        {
            var rList = new List<uint>();
            if (columnNames.Any())

                foreach (var name in columnNames)
                {
                    rs.GetFieldVal(name, out uint temp);
                    if (shouldRun(temp))
                    {
                        rList.Add(temp);
                    }

                }
            return rList;
        }

这行得通。但是,如果我将其更改为此,结果将是生成集合中的所有最终项目(尽管 Count 是正确的值)。

public static IEnumerable<uint> GetFieldVals(this DataSource rs, IEnumerable<string> columnNames, Predicate<uint> shouldRun)
{

    if (!columnNames.Any()) yield break;

    foreach (var name in columnNames)
    {
        rs.GetFieldVal(name, out uint temp);
        if (shouldRun(temp))
        {
            yield return temp;
        }

    }
}

什么给了?

编辑 谢谢大家的cmets。我写的有点匆忙,然后有一个忙碌的周末,所以我无法正确解决这个问题。我现在就这样做。你们都是 100% 正确的,我遗漏了太多。

我正在尝试使用笨重的 DataSource api 并使用它创建一个 IEnumerable 值对象项(使用起来更容易、更灵活)。我正在使用工厂来实现它以保持便携性;我的工厂方法实现调用了我在原始帖子中编写的代码。这是我的 valueobject 的示例:

public class MyTableDataObject : IDataObject<uint>
{
    public uint ID { get; set; }
    public string Name { get; set; }

    //MOAR properties

    public IEnumerable<uint> SomeCollection { get; set; }

    //MOAR properties

}

我谈到的问题发生在我的 valueobject 中有一些类型的集合作为属性(即上面的 sn-p 中的“SomeCollection”)

FWIW,这是我从原始帖子传递给扩展方法的列名集合的代码。

    public static IEnumerable<string> ColumnNames
    {
        get
        {

            yield return "COLUMNNAME00";
            yield return "COLUMNNAME01";
            yield return "COLUMNNAME02";
            yield return "COLUMNNAME03";
            yield return "COLUMNNAME04";
            yield return "COLUMNNAME05";
            yield return "COLUMNNAME06";
            yield return "COLUMNNAME07";
            yield return "COLUMNNAME08";
            yield return "COLUMNNAME09";
            yield return "COLUMNNAME10";
            yield return "COLUMNNAME11";
            yield return "COLUMNNAME12";
            yield return "COLUMNNAME13";
            yield return "COLUMNNAME14";
            yield return "COLUMNNAME15";
        }
    }

这是调用代码。

var rs = new DataSource();
rs.Open("Select * From MyTable");

//The Generic type on the enumerable indicates the type of the identifier of the items, not that the Enumerable is itself a list of uints. Do not get confused by this!
var dse = new DataSourceEnumerable<uint>(rs, new MyTableDataObjectFactory());

using (var writer = new MyWriterFacade("MyOutput.json"))
{
    var json = new JsonSerializer(); //Newtonsoft.Json lib
    var str = JsonConvert.SerializeObject(dse, Formatting.Indented);
    writer.Write(str);   

}

虽然输出的 json 文件的值大部分是正确的,但当我使用 yield 关键字时,每个“SomeCollection”都有相同的项目(我相信这是最后一个项目的 SomeCollection 值)。但是,当我不使用 yield 并使用更传统的代码时,json 输出说明了文件中每个 SomeCollection 的正确值。

这是实际Enumerable中的代码:

public DataSourceEnumerable(DataSource ds, DataObjectFactory<T, DataSource> factory)
{
    ds.MoveFirst();
    innerList = new List<IDataObject<T>>();

    _enumerator = Create(ds, factory, innerList);
}

public static IEnumerator<IDataObject<T>> Create(DataSource ds, DataObjectFactory<T, DataSource> factory,
    IList<IDataObject<T>> innerList)
{   
    while (!ds.Eof)
    {
        innerList.Add(factory.InitializeDataObject<object, object>(ds));
        ds.MoveNext();
    }
    return new DataSourceEnumerator(innerList);
}

如果有人可以更好地为我分解一下,我希望能对此有所了解。欣赏!

【问题讨论】:

  • 请出示你用来调用这个方法的代码,我想看看你用的是什么迭代机制
  • 这段代码看起来不错 - 似乎它可能与您调用它的方式有关。你也可以包括调用代码吗?
  • 如何迭代IEnumerable&lt;uint&gt; 结果?看起来,您已经在 linq 方法的循环中某处捕获了变量
  • 请制作一个完整、可独立运行的小程序来重现错误并发布。通过这样做,您将自己发现缺陷,或者您将以一种让别人实际运行并理解它的方式呈现代码。您在此处粘贴的代码很好,因此很难理解问题所在。
  • 你能说一下为什么在foreach 循环之前调用Any 吗?如果集合为空,foreach 将跳过正文,因此这似乎是无用的代码。

标签: c# ienumerable yield


【解决方案1】:

所示代码中唯一真正的区别与时间有关。使用列表版本,在调用方法时执行操作。使用 yield 版本,它会在稍后调用,当方法的 result 实际上是 iterated

现在:事情有时会在调用返回序列的方法和迭代该序列之间发生变化。例如,数据源或字段序列参数的内容可能会发生变化。或者谓词的逻辑可能会改变,通常是由于“捕获的变量”。所以:区别在于调用这个的代码,我们看不到。但是:在调用方法和实际迭代它(foreach 等)之间寻找时间

【讨论】:

    猜你喜欢
    • 2020-03-27
    • 2019-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多