Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#LINQ对相同数据的多重评估_C#_Linq_Lazy Evaluation - Fatal编程技术网

C#LINQ对相同数据的多重评估

C#LINQ对相同数据的多重评估,c#,linq,lazy-evaluation,C#,Linq,Lazy Evaluation,给定一个包含(并初始化一次)IEnumarable的类: 这将打印20次“转换:”和“值:” 我知道将值保存为列表(例如使用ToList())可以解决这一问题,但我的理解是,一旦对值进行了计算,这些值将从内存中使用(就像我使用了Lazy,然后使用Values.value),为什么情况不一样?这是IEnumerable的正常行为。在foreach循环中调用每个项时,实际上会为集合中的每个项调用投影调用Select(但显然只调用了一次) 因此,当您使用foreach循环时,IEnumerable对象

给定一个包含(并初始化一次)IEnumarable的类:

这将打印20次“转换:”和“值:”


我知道将值保存为列表(例如使用
ToList()
)可以解决这一问题,但我的理解是,一旦对值进行了计算,这些值将从内存中使用(就像我使用了
Lazy
,然后使用
Values.value
),为什么情况不一样?

这是
IEnumerable
的正常行为。在
foreach
循环中调用每个项时,实际上会为集合中的每个项调用投影调用
Select
(但显然只调用了一次)

因此,当您使用
foreach
循环时,
IEnumerable
对象正在调用枚举器,并获取集合中的下一项(如果有可用项),类似于状态机

当foreach循环中的下一个项被请求时,它会跟踪被枚举的当前项,并再次调用它,从而导致再次调用
Convert
方法。

值具体化为一个集合(例如,放入
列表
):

公共类MyClass
{
私有列表m_值;
...
公共IEnumerable值{
得到{
//而不是枚举和计算项目
//我们返回计算项的集合
返回m_值;
}
专用设备{
//现在,值将被枚举一次,并且项
//将存储在m_值集合中
m_Values=value.ToList();
}
}
... 
}
如果要以惰性方式执行此操作,请执行以下操作:

公共类MyClass
{
私人清单m_价值清单;
私有IEnumerable m_值;
...
公共IEnumerable值{
得到{
//如果缓存不存在,则具体化
如果(m_ValuesList==null)
m_ValuesList=m_Values.ToList();
//而不是枚举和计算项目
//我们返回计算项的集合
返回m_值列表;
}
专用设备{
m_值=值;
//丢弃缓存(物化集合)
m_ValuesList=null;
}
}
... 
}

具体化(
.ToArray()
.ToList()
),即将结果存储在集合中,然后计算一次。看看这个:我想问一下在这种情况下使用LINQ有什么好处,但我看到了关于
public class MyClass
{
    public MyClass()
    {
        Values = Sequence(0, 10).Select(i => Convert(i));
    }

    public IEnumerable<string> Values { get; private set; }

    private static string Convert(int i)
    {
        string iStr = i.ToString();
        Console.WriteLine("Convert: " + iStr);
        return iStr;
    }

    private static IEnumerable<int> Sequence(int start, int end)
    {
        return Enumerable.Range(start, end - start + 1);
    }
}
public class MyClass
{
    private List<string> m_Values;

    ...

    public IEnumerable<string> Values { 
      get {
        // Instead of enumerating and computing items
        // we return the collection of computed items
        return m_Values;
      }
      private set {
        // Now value will be enumerated once and items
        // will be stored in the m_Values collection
        m_Values = value.ToList();
      }
    }

    ... 
}
public class MyClass
{
    private List<string> m_ValuesList;
    private IEnumerable<string> m_Values; 

    ...

    public IEnumerable<string> Values { 
      get {
        // Materialize if cache doesn't exist
        if (m_ValuesList == null)
          m_ValuesList = m_Values.ToList();

        // Instead of enumerating and computing items
        // we return the collection of computed items 
        return m_ValuesList;
      }
      private set {
        m_Values = value;
        // drop cache (materialized collection) 
        m_ValuesList = null;
      }
    }

    ... 
}