【发布时间】:2022-08-06 11:12:57
【问题描述】:
我在 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 => /*...*/);
我需要有关如何派生与 for 循环匹配的 lambda 表达式的正确主体的帮助。
提前致谢!
编辑 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);
那行得通吗?
标签: c# performance linq query-optimization boolean-logic