提问人:Dr. Brian Hart 提问时间:7/21/2022 最后编辑:Dr. Brian Hart 更新时间:8/6/2022 访问量:65
如何对以下循环进行 LINQ 化?
How to LINQ-ify the following loop?
问:
我在 C# 程序中有一个方法。它枚举特定文件夹中的所有文件,然后遍历列表。对于每个文件,我都阅读了所有使用在上面的行。我只想处理一个文件,如果它包含一个类,无论是传统的,还是其名称以某个短语开头并且不以单词结尾的,我希望在包含类---声明的行中找到行索引,即部分。.cs
File.ReadAllLines
static,
abstract,
Tests.
public static class Foo
假设我接受 的结果并调用它来创建一个 ,我希望使用该方法使用谓词找到与我的条件(如果存在)匹配的行的索引。File.ReadAllLines
ToList()
List<string>
FindIndex
我的问题是:写这样一个谓语的好方法是什么?
我意识到我可能会使用更复杂的方法,但我只是将此代码放入一个快速而肮脏的 LINQPad 脚本中。所以,我不必变得超级花哨。
让我向你展示我到目前为止所拥有的(假设最外层的命名空间和类已经适当地声明了):
void Main()
{
var files = Directory
.EnumerateDirectories(
Path.Combine(
Environment.GetFolderPath(
Environment.SpecialFolder.UserProfile
), @"source\repos\astrohart\MFR"
), "*", SearchOption.TopDirectoryOnly
).SelectMany(
x => Directory.EnumerateFiles(
x, "FileSystemEntry*.cs", SearchOption.AllDirectories
)
)
.Where(x => !"FileSystemEntry.cs".Equals(Path.GetFileName(x)))
.ToList();
if (files == null || !files.Any()) return;
foreach (var file in files)
{
var contents = string.Empty;
try
{
contents = File.ReadAllText(file);
}
catch (Exception ex)
{
Console.WriteLine($"ERROR: {ex.Message}");
contents = string.Empty;
}
if (string.IsNullOrWhiteSpace(contents)) continue;
if (contents.Contains("[TestFixture]")) continue;
if (contents.Contains("[Log(AttributeExclude = true)]")) continue;
file.Dump();
var lines = new List<string>();
lines.TrimExcess();
try
{
lines = File.ReadAllLines(file).ToList();
}
catch (Exception ex)
{
Console.WriteLine($"ERROR: {ex.Message}");
lines = new List<string>();
lines.TrimExcess();
}
if (lines == null || !lines.Any()) continue;
var index = -1;
for (var i = 0; i < lines.Count; i++)
{
var currentLine = lines[i].Trim();
if (currentLine.EndsWith("Tests")) continue;
if (currentLine.StartsWith("public static class FileSystemEntry"))
{
index = i;
break;
}
if (currentLine.StartsWith("public class FileSystemEntry"))
{
index = i;
break;
}
if (currentLine.StartsWith("public abstract class FileSystemEntry"))
{
index = i;
break;
}
}
if (index < 0) continue;
/*...*/
}
}
如何翻译循环:for
var index = -1;
for (var i = 0; i < lines.Count; i++)
{
var currentLine = lines[i].Trim();
if (currentLine.EndsWith("Tests")) continue;
if (currentLine.StartsWith("public static class FileSystemEntry"))
{
index = i;
break;
}
if (currentLine.StartsWith("public class FileSystemEntry"))
{
index = i;
break;
}
if (currentLine.StartsWith("public abstract class FileSystemEntry"))
{
index = i;
break;
}
}
if (index < 0) continue;
因此,进入呼叫:
var index = lines.FindIndex(currentLine => /*...*/);
我需要有关如何派生与循环功能相匹配的 lambda 表达式的正确主体的帮助。for
提前致谢!
编辑 1
我眯起眼睛看了看我的环。我正在寻找专门用于该方法的谓词。我想得更仔细一点,我发现也许我可以侥幸逃脱:FindIndex
var index = lines.FindIndex(currentLine => !currentLine.Trim.EndsWith("Tests") && currentLine.Trim().StartsWith("public static class FileSystemEntry") || currentLine.Trim().StartsWith("public class FileSystemEntry") || currentLine.Trim().StartsWith("public abstract class FileSystemEntry"));
也许我可以实现一个扩展方法
public static bool StartsWithAnyOf(this string value, params string[] testStrings)
{
var result = false;
try
{
if (string.IsNullOrWhiteSpace(value.Trim())) return result;
if (testStrings == null || !testStrings.Any()) return result;
foreach(var element in testStrings)
if (value.Trim().StartsWith(element))
{
result = true;
break;
}
}
catch
{
result = false;
}
return result;
}
然后我会声明另一个方法:
public static bool KeepLine(string currentLine)
{
if (string.IsNullOrWhiteSpace(currentLine.Trim())) return false;
if (currentLine.Trim().EndsWith("Tests")) return false;
return currentLine.StartsWithAnyOf(
"public static class FileSystemEntry",
"public class FileSystemEntry",
"public abstract FileSystemEntry"
);
}
然后这样使用它:
var index = lines.FindIndex(KeepLine);
那行得通吗?
答:
我还没有对此进行彻底测试,但如果我与上面提供的原始代码进行比较,它似乎通过了基本的理智。请注意,在衡量性能时,这并不是最好的。具有匿名函数的“foreach”循环存在缺陷,您无法摆脱匿名函数。摆脱 foreach 的唯一方法是运行所有 foreach 语句。为了保留条件与行内容匹配的第一个索引,我在else if()比较语句中使用了索引。这意味着 foreach 循环将对所有行运行,即使首次找到匹配行。
lines.ForEach((l) =>
{
if (l.EndsWith("Tests")) ;
else if (index ==0 && (l.StartsWith("public static class FileSystemEntry") ||
l.StartsWith("public class FileSystemEntry") ||
l.StartsWith("public abstract class FileSystemEntry")))
{
index = lines.IndexOf(l);
}
});
评论
ForEach
return;
break;
ForEach
return;
continue
FindIndex
ForEach
下一个:使用整数和字符串的布尔逻辑
评论