首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使"var“成为全局的或持久的?

如何使"var“成为全局的或持久的?
EN

Stack Overflow用户
提问于 2012-08-17 22:23:32
回答 5查看 221关注 0票数 0

我正在编写一个使用文件系统的应用程序。当应用程序第一次启动时,它会运行一个快速例程,将请求的文件和文件夹加载到内存中,以便稍后进行(时间密集型)处理。(请参阅下面的代码)。在这一点上,它给出了将要处理的文件数,这对于显示进度条很重要。

一旦我有了计数和文件数据,我需要存储数据以供以后处理(例如,作为全局变量或属性或类)。问题是,由于它使用的是LINQ,所以必须将其存储为"var“。当我分解并检查变量时,它被存储为一个相当复杂的SelectQueryOperator和AnonymousType的混合。

我的第一个想法是继续循环遍历数据,并将其转换为我可以存储为List<>的简单数据(例如,存储文件名和路径),但这样做需要几分钟-最多10分钟或更长时间-处理。为了进行处理,我将不得不遍历所有这些数据,而且我的用户不可能先坐下来等待列表的建立。

我如何存储这些数据,以便我以后可以访问它,而不必首先将其转换为其他数据?

代码语言:javascript
运行
复制
var fileNames = 
from dir in Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories)
select dir;

var fileContents = from file in fileNames.AsParallel() 
// Use AsOrdered to preserve source ordering 
let extension = Path.GetExtension(file)
let Text = File.ReadAllText(file)
select new { Text, FileName = file }; 
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2012-08-18 00:28:46

让我们稍微简化一下,并在可能的情况下显式地使用var

代码语言:javascript
运行
复制
var fileNames = 
from dir in Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories)
select dir;

这与以下内容完全相同:

代码语言:javascript
运行
复制
var fileNames = Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories);

这与以下内容完全相同:

代码语言:javascript
运行
复制
IEnumerable<string> fileNames = Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories)

现在来看一下:

代码语言:javascript
运行
复制
var fileContents = from file in fileNames.AsParallel() 
// Use AsOrdered to preserve source ordering 
let extension = Path.GetExtension(file)
let Text = File.ReadAllText(file)
select new { Text, FileName = file }; 

通常情况下,使用单行查询不会提高可读性,但为了便于讨论,它将有助于将我们的对象创建放在一个地方:

代码语言:javascript
运行
复制
var fileContents = from file in fileNames.AsParallel() 
select new { Text = File.ReadAllText(file), FileName = Path.GetExtension(file) }; 

这是匿名TParallelQuery<T>。为了让它成为我们可以存储的东西,我们需要停止使用匿名类:

代码语言:javascript
运行
复制
private class NameAndContents
{
   public string Text{get;set;}
   public string FileName{get;set;}
}

ParallelQuery<NameAndContents> fileContents = from file in fileNames.AsParallel() 
select new NameAndContents{ Text = File.ReadAllText(file), FileName = Path.GetExtension(file) }; 

现在没有什么可以阻止您将其存储在ParallelQuery<NameAndContents>类型的字段中。

您可能希望通过两种方式来检查这里的逻辑:

  1. Directory.EnumerateFiles的工作原理是,它需要知道给定迭代的值才能计算下一次迭代。(它基于FindNextFile Windows API函数)。这使得它在并行化方面表现不佳。很难预测ReadAllText所涉及的固有等待会有多大程度的平衡。我不仅会在非并行版本上测试它,而且在任何更改后我都会重新测试,因为任何更改都会以一种新的方式打破这种平衡。
  2. 这里最大的冲击是ReadAllText。如果有可能用一种更按需使用文本的方式来取代它,那么这可能是一个巨大的胜利。
票数 1
EN

Stack Overflow用户

发布于 2012-08-17 22:27:22

的问题是,由于它使用的是LINQ,所以它必须被存储为"var“。

不,LINQ没有任何需要你使用var的地方。基本上,var允许您在方法中以强类型的方式使用匿名类型。

您所需要做的就是将您的匿名类型转换为命名类型,您将获得与使用var完全相同的性能。当您使用ToList时,您看到的不同之处很简单:在计算查询之前,它实际上不会做任何事情--我怀疑您根本不会访问文件系统。(不清楚为什么一开始就有Directory.EnumerateFiles的查询表达式。)

您要么需要提前加载数据,要么不需要-从您的问题中看不出这一点,但var部分与此完全正交。

顺便说一句,在文件系统上使用并行处理可能会阻碍而不是帮助。

票数 2
EN

Stack Overflow用户

发布于 2012-08-17 22:27:26

不能对任何非局部变量使用var。(This is why.)如果您真的讨厌需要维护您的代码的人,那么您可以将其存储为objectdynamic,并使用几种可能的方法之一从已存储为object的匿名类型中获取信息,但这可能不是一个好主意。

实际上,最好的办法就是创建一个具有TextFileName属性的新类型,并使用该类型而不是匿名类型。对于未来的开发者来说,这是最简单和最不重要的选择。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12007640

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档