简体   繁体   English

如果更改了 IEnumerable 数据源,它会更改结果

[英]If IEnumerable data source is changed, it changes the results

Given the following code:给定以下代码:

using System.Linq;              
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        //Init data
        char[] chars = new char[10];
        FillData(chars);

        // Write the initial data
        PrintContents("Initial data:", chars);
        //Take some data:
        IEnumerable<char> acc = chars.Take(3);
        //View data
        PrintContents("Enum:", acc);

        //Edit data
        chars[0] = 'z';
        chars[1] = 'z';
        chars[2] = 'z';

        //View data again
        PrintContents("Enum after modifing source:", acc);

        //Restart data
        chars = new char[5];
        FillData(chars);

        //View data when source is replaced
        PrintContents("Enum after new source:", acc);
    }

    //Gets a ref
    private static void FillData(char[] data)
    {
        for(int i = 0; i < data.Length; i++)
        {
            data[i] = (char)('a' + i);
        }
    }

    private static void PrintContents(string what, IEnumerable<char> src)
    {
        System.Console.WriteLine(what);
        string s = "";
        foreach(char ch in src)
        {
            s += ch;
        }
        if(s.Length > 0)
        {
            System.Console.WriteLine(s);
        }
    }
}

I get this output:我得到这个 output:

Initial data:
abcdefghij
Enum:
abc
Enum after modifing source:
zzz
Enum after new source:
zzz

I know about the deferred execution, but is that the expected behaivour?我知道延迟执行,但这是预期的行为吗? This means I should ever reuse an IEnumerable or any data used on an IEnumerable without creating a new collection as I may change the results on a program.这意味着我应该在不创建新集合的情况下重用 IEnumerable 或在 IEnumerable 上使用的任何数据,因为我可能会更改程序的结果。

This means that the IEnumerable will hold a reference to the data sources as well even if they are not used by the visible code as well and will not be Garbage Collected until the IEnumerable itself is to be collected.这意味着 IEnumerable 也将持有对数据源的引用,即使它们也未被可见代码使用,并且在收集 IEnumerable 本身之前不会被垃圾收集。

I have been using IEnumerable a lot on a recent project and the more I see them the less I like them.我在最近的一个项目中经常使用 IEnumerable,我看到它们越多,我就越不喜欢它们。 Don't take me wrong, Linq does a great job but I would prefer it to sometimes return the same type of the source.不要误会我的意思,Linq 做得很好,但我希望它有时返回相同类型的源。

Yes, this is expected behavior.是的,这是预期的行为。

You should look at results of LINQ methods as "compute result when I enumerate" and not as "collection of items".您应该将 LINQ 方法的结果视为“我枚举时的计算结果”,而不是“项目集合”。 To me it makes easier to understand that when I enumerate it the second time it will again compute the results as I walk through items.对我来说,更容易理解的是,当我第二次枚举它时,它会在我遍历项目时再次计算结果

It matters a lot in cases when source data may change (like the sample in the question) or when obtaining result is costly (querying DB is very common case of hidden cost).在源数据可能发生变化(如问题中的样本)或获取结果成本高昂(查询数据库是隐藏成本的常见情况)的情况下,这很重要。 Unfortunately there is no common way to clarify whether enumerable is costly (ie DB) or essentially free (ie list) and both cases - repeated querying for live data or repeated enumeration of cached result - are commonly used.不幸的是,没有通用的方法来阐明 enumerable 是昂贵的(即 DB)还是本质上是免费的(即 list),并且这两种情况 - 重复查询实时数据或重复枚举缓存结果 - 都是常用的。 IQueryable is somewhat an indication of costly, lazily evaluated enumerable but just having IEnumerable does not tell anything about how costly/up-to-date results would be. IQueryable在某种程度上表明代价高昂,懒惰地评估可枚举,但仅仅拥有IEnumerable并不能说明任何关于代价高昂/最新结果的信息。

On your concern that queries keep data sources alive for possible longer than you expect - yes, it is a concern.您担心查询使数据源保持活动的时间可能比您预期的要长 - 是的,这是一个问题。 You should understand what is expected usage of the result and consider if returning non-lazy result is better (ie with .ToList() ).您应该了解结果的预期用途,并考虑返回非惰性结果是否更好(即使用.ToList() )。 Be careful when getting data from disposable sources (DB, files, and non-seekable source like network streams) - it is often easier to force evaluation of the query and return List (or any other non-lazy) collection to have control over how and when data source is disposed.从一次性来源(数据库、文件和不可搜索的来源,如网络流)获取数据时要小心——通常更容易强制评估查询并返回List (或任何其他非惰性)集合以控制如何以及何时处理数据源。

For example you should strongly consider passing non-lazy enumerables to ASP.Net MVC views - data may be easily iterated multiple times to render (even .Count() is an iteration) so lazily computed enumerable on DB can easily double or triple cost of rendering the page.例如,您应该强烈考虑将非延迟枚举传递给 ASP.Net MVC 视图 - 数据可能很容易迭代多次以呈现(甚至.Count()是一次迭代),因此在 DB 上延迟计算的可枚举可以轻松地增加一倍或三倍的成本渲染页面。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何获取数据结果到IEnumerable? - How to get the data results to IEnumerable? 数据源是无效的类型。 它必须是IListSource,IEnumerable或IDataSource - Data source is an invalid type. It must be either an IListSource, IEnumerable, or IDataSource IEnumerable.Contains()继续查询数据源而不是内存 - IEnumerable.Contains() keeps querying data source instead of memory 数据源是无效的类型。 它必须是IListSource,IEnumerable或IDataSource - Data source is an invalid type. It must be either an IListSource, IEnumerable, or IDataSource 数据源是无效类型。它必须是IListSource,IEnumerable或IDataSource - Data source is an invalid type. It must be either an IListSource, IEnumerable, or IDataSource 数据源是无效的类型。 它必须是IListSource,IEnumerable或IDataSource - Data source is an invalid type. It must be either an IListSource, IEnumerable, or IDataSource 数据源是无效类型。 它必须是 IListSource、IEnumerable 或 IDataSource - Data source is an invalid type. It must be either an IListSource, IEnumerable, or IDataSource 使用IEnumerable &lt;&gt;源填充Dictionary &lt;&gt; - filling a Dictionary<> with an IEnumerable<> source 将LINQ结果与IEnumerable结合 - Joining LINQ results with IEnumerable 对IEnumerable <T>结果进行分区 - Partitioning IEnumerable<T> Results
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM