You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将C#中的for循环转换为FindIndex的Predicate表达式?

问题:将类声明行查找逻辑改写为FindIndex+Predicate形式

我在C#程序里写了个方法,会枚举指定文件夹下所有.cs文件并遍历。对每个文件,用File.ReadAllLines读取所有行,只处理那些包含名称以特定短语开头且不以Tests结尾的常规、static或abstract类的文件,同时要定位到类声明行(比如public static class Foo)的索引。

我已经把File.ReadAllLines的结果转成了List<string>,想把现有的for循环逻辑改成用lines.FindIndex(currentLine => /*...*/)的形式,自己试了两种写法,想问问这些方案是否可行。


现有循环实现代码

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;

我的两种尝试写法

尝试1:直接Lambda写法

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"));

尝试2:扩展方法+判断方法写法

扩展方法定义

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);

方案可行性分析与优化建议

尝试1:直接Lambda写法

可行,但需修正两个问题:

  1. 逻辑运算符优先级错误:&&优先级高于||,原写法会被解析为「(!Tests结尾 && 静态类) || 常规类 || 抽象类」,和原循环逻辑(先排除Tests结尾的行,再匹配类声明)不符。需给||部分加括号修正:
    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")));
    
  2. 重复调用Trim():每一行多次调用Trim()浪费性能,可提前缓存修剪后的结果。

尝试2:扩展方法+判断方法写法

整体可行,但有细节优化空间:

  1. 避免重复Trim():扩展方法中多次调用value.Trim(),建议缓存结果:var trimmedValue = value.Trim();
  2. 移除冗余try-catch:Trim()和StartsWith()正常场景不会抛异常,只需提前判断value是否为null即可
  3. 修正参数笔误:KeepLine方法里第三个前缀少了class,应改为"public abstract class FileSystemEntry"

优化后的扩展方法:

public static bool StartsWithAnyOf(this string value, params string[] testStrings)
{
    if (string.IsNullOrWhiteSpace(value)) return false;
    var trimmedValue = value.Trim();
    if (string.IsNullOrWhiteSpace(trimmedValue)) return false;
    if (testStrings == null || testStrings.Length == 0) return false;

    foreach (var element in testStrings)
    {
        if (trimmedValue.StartsWith(element))
        {
            return true;
        }
    }
    return false;
}

更简洁的替代写法

可以把类声明前缀提取成数组,结合LINQ的Any()方法,既避免重复操作,又让逻辑更清晰:

var classPrefixes = new[] 
{ 
    "public static class FileSystemEntry", 
    "public class FileSystemEntry", 
    "public abstract class FileSystemEntry" 
};

var index = lines.FindIndex(line => 
{
    var trimmedLine = line.Trim();
    return !trimmedLine.EndsWith("Tests") && classPrefixes.Any(prefix => trimmedLine.StartsWith(prefix));
});

内容的提问来源于stack exchange,提问作者Dr. Brian Hart

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 10:24:46