使用LINQ更新字符串数组

| 我正在尝试创建一种使用LINQ用新版本字符串更新AssemblyInfo文件的方法。我可以成功提取需要更新的字符串,但是不确定如何更新集合中的项目。我是LINQ的新手,所以我们为您提供任何建议!
private void UpdateVersion(string file, string version)
    {
        string[] asmInfo = File.ReadAllLines(file);
        var line = asmInfo.Single(x => x.Trim().StartsWith(\"[assembly: AssemblyVersion\"));
        line = \"[assembly: AssemblyVersion\\\"\" + version + \"\\\")]\";

        // This doesn\'t work - it\'s writing the original file back
        File.WriteAllLines(file, asmInfo);
    }
    
已邀请:
           我是LINQ的新手,所以我们为您提供任何建议! Linq的主要设计目的是查询,汇总和过滤数据,而不是直接修改现有数据。您可以使用它来制作数据的修改后的副本,并用该副本覆盖原始数据。 不过,您遇到的问题并非完全是因为Linq。 让我们回顾一下您的代码:
string[] asmInfo = File.ReadAllLines(file);
您正在将文件的所有行复制到内存中的字符串数组中。
var line = asmInfo.Single(x => x.Trim().StartsWith(\"[assembly: AssemblyVersion\"));
您正在查询所有行,并将行(按值或多或少)复制到变量
line
中。
line = \"[assembly: AssemblyVersion\\\"\" + version + \"\\\")]\";
您正在用不同的内容覆盖复制的行。这不会修改原始数组。
File.WriteAllLines(file, asmInfo);
您正在将原始数组写回到文件中。您没有更改数组,因此不会在文件中看到任何更改。 解决此问题的几种方法: 按照当前操作,复制出数组,找到要更改的行的索引,然后修改数组(按索引)。此选项根本不使用Linq。 使用linq制作数据的转换副本,然后将整个转换副本写回。此选项使用linq,但不利用其功能。 停止使用
File.ReadAllLines
/
File.WriteAllLines
,并一次读/写一行。该选项实际上利用了Linq的功能,但是最复杂。 修改数组 此方法根本不使用Linq:
string[] asmInfo = File.ReadAllLines(file);
int lineIndex = Array.FindIndex(asmInfo,
    x => x.Trim().StartsWith(\"[assembly: AssemblyVersion\"));
asmInfo[lineIndex] = \"[assembly: AssemblyVersion\\\"\" + version + \"\\\")]\";
File.WriteAllLines(file, asmInfo);
假设您的文件很小,这是完成任务的相当标准的方法。 查询并制作数据的转换副本,然后写出副本 此方法更像Linq:
string[] asmInfo = File.ReadAllLines(file);
var transformedLines = asmInfo.Select(
    x => x.Trim().StartsWith(\"[assembly: AssemblyVersion\")
        ? \"[assembly: AssemblyVersion\\\"\" + version + \"\\\")]\"
        : x
    );
File.WriteAllLines(file, asmInfo.ToArray());
与前面的示例相比,这更像Linq。但这实际上效率较低,因为
File.WriteAllLines
不能取
IEnumerable<string>
。因此,您不得不叫
ToArray
。当您调用
ToArray
(或
ToList
)时,将运行整个查询并将其复制到新的数组中,因此您将拥有文件的两个副本。 如果
File.WriteAllLines
取了
IEnumerable<string>
,那么您将不必制作额外的副本,并且每行都将在查询仍在运行时写入。 一次读写一行 此选项是最有效的,并且实际上显示了Linq的某些优点-更具体地说,是ѭ17的优点,这是Linq的大部分功能都来自于此。
public static class FileStreamExtensions
{
    public static IEnumerable<string> GetLines(this FileStream stream)
    {
        using (var reader = new StreamReader(stream))
        {
            string line;
            while ((line = reader.ReadLine()) != null)
                yield return line;
        }
    }

    public static void WriteLines(this FileStream stream, IEnumerable<string> lines)
    {
        using (var writer = new StreamWriter(stream))
        {
            foreach (string line in lines)
            {
                writer.WriteLine(line);
            }
        }
    }
}

private void UpdateVersion(string file, string version)
{
    using (FileStream inputFile = File.OpenRead(file))
    {
        string tempFilePath = Path.GetTempFileName();

        var transformedLines = inputFile.GetLines().Select(
            x => x.Trim().StartsWith(\"[assembly: AssemblyVersion\")
                ? \"[assembly: AssemblyVersion\\\"\" + version + \"\\\")]\"
                : x
            );

        using (FileStream outputFile = File.OpenWrite(tempFilePath))
        {
            outputFile.WriteLines(transformedLines);
        }

        string backupFilename = Path.Combine(Path.GetDirectoryName(file), Path.GetRandomFileName());
        File.Replace(tempFilePath, file, backupFilename);
    }
}
这需要更多代码,因为: 现在,数据的中间副本位于临时文件中,而不是内存中的数组中。 流类本身并不提供逐行的枚举器,因此我们自己构建了它们。 如果在调试器中运行它,并在break19ѭ和
writer.WriteLine
语句上设置断点,则会看到一些有趣的东西。读取代码和写入代码(或多或少)同时运行。首先读取一行,然后将其写入。 这是因为
IEnumerable
yield return
,这是Linq不仅仅是语法糖的主要原因之一。     
        我建议为此使用
Regex
private static void UpdateVersion(string file, string version)
{
    var fileContent = File.ReadAllText(file);
    var newFileContent = Regex.Replace(
        fileContent,
        @\"(?<=AssemblyVersion\\(\"\")(?<VersionGroup>.*?)(?=\"\"\\))\",
        version);
    File.WriteAllText(file, newFileContent);
}
您仍然可以使用LINQ来执行此操作,但是我想这会降低效率,并且更容易出错。
private static void UpdateVersion(string file, string version)
{
    var linesList = File.ReadAllLines(file).ToList();
    var line = linesList.Single(x => x.Trim().StartsWith(\"[assembly: AssemblyVersion\"));
    linesList.Remove(line);
    linesList.Add(\"[assembly: AssemblyVersion(\\\"\" + version + \"\\\")]\");
    File.WriteAllLines(file, linesList.ToArray());
}
    
        您可能不应该尝试使用LINQ修改原始查询源,因为它笨拙且容易出错,而不是LINQ的“样式”。 相反,您可以使用LINQ作为筛选器来创建新的数组。我们需要做的就是稍微重新排列您的代码:
private void UpdateVersion(string file, string version)
{
    string[] asmInfo = File.ReadAllLines(file);
    asmInfo = asmInfo.Select(x => x.Trim().StartsWith(\"[assembly: AssemblyVersion\") ?
        \"[assembly: AssemblyVersion\\\"\" + version + \"\\\")]\" : x).ToArray();

    File.WriteAllLines(file, asmInfo);
}
    

要回复问题请先登录注册