如何查找 C# 项目中的所有硬编码值(解决方案)?

2024-02-20

这个问题不仅仅询问硬编码字符串,还询问幻数等。

有没有办法找到所有硬编码值即字符串,神奇的数字VS 中的 C# 项目/解决方案中没有什么?

引发这个问题的是我正在查看的一个项目,我刚刚发现一个字符串值被硬编码重复了 174 次!


你能做的就是编程Roslyn https://github.com/dotnet/roslyn,镇上(不那么)新的酷孩子。它允许您轻松解析 C#(或 VB.NET)项目。然后您可以访问检测到的节点并检查您真正想要检查的内容。检测机器的魔法文字并不总是像人类看起来那么容易。例如,1真的是一个神奇的数字吗?我个人认为不是,但是2更可疑......

不管怎样,这是一个小样本,我相信它可以完成大部分工作,但它可以/应该改进,也许可以定制您确切的业务需求或规则(这非常有趣)。

注意 Roslyn 还可以直接在 Visual Studio 上下文中使用,因此您可以将此示例转换为所谓的诊断(Visual Studio 的扩展),可以帮助您直接在 IDE 中运行。有这样的示例:示例和演练 https://github.com/dotnet/roslyn/wiki/Samples-and-Walkthroughs

class Program
{
    static void Main(string[] args)
    {
        var text = @" 
public class MyClass 
{ 
public void MyMethod() 
{ 
    const int i = 0; // this is ok
    decimal d = 11; // this is not ok
    string s = ""magic"";
    if (i == 29) // another magic
    {
    }
    else if (s != ""again another magic"")
    {
    }
}
}";
        ScanHardcodedFromText("test.cs", text, (n, s) =>
        {
            Console.WriteLine(" " + n.SyntaxTree.GetLineSpan(n.FullSpan) + ": " + s);
        }).Wait();
    }

    public static async Task ScanHardcodedFromText(string documentName, string text, Action<SyntaxNodeOrToken, string> scannedFunction)
    {
        if (text == null)
            throw new ArgumentNullException("text");

        AdhocWorkspace ws = new AdhocWorkspace();
        var project = ws.AddProject(documentName + "Project", LanguageNames.CSharp);
        ws.AddDocument(project.Id, documentName, SourceText.From(text));
        await ScanHardcoded(ws, scannedFunction);
    }

    public static async Task ScanHardcodedFromSolution(string solutionFilePath, Action<SyntaxNodeOrToken, string> scannedFunction)
    {
        if (solutionFilePath == null)
            throw new ArgumentNullException("solutionFilePath");

        var ws = MSBuildWorkspace.Create();
        await ws.OpenSolutionAsync(solutionFilePath);
        await ScanHardcoded(ws, scannedFunction);
    }

    public static async Task ScanHardcodedFromProject(string solutionFilePath, Action<SyntaxNodeOrToken, string> scannedFunction)
    {
        if (solutionFilePath == null)
            throw new ArgumentNullException("solutionFilePath");

        var ws = MSBuildWorkspace.Create();
        await ws.OpenProjectAsync(solutionFilePath);
        await ScanHardcoded(ws, scannedFunction);
    }

    public static async Task ScanHardcoded(Workspace workspace, Action<SyntaxNodeOrToken, string> scannedFunction)
    {
        if (workspace == null)
            throw new ArgumentNullException("workspace");

        if (scannedFunction == null)
            throw new ArgumentNullException("scannedFunction");

        foreach (var project in workspace.CurrentSolution.Projects)
        {
            foreach (var document in project.Documents)
            {
                var tree = await document.GetSyntaxTreeAsync();
                var root = await tree.GetRootAsync();
                foreach (var n in root.DescendantNodesAndTokens())
                {
                    if (!CanBeMagic(n.Kind()))
                        continue;

                    if (IsWellKnownConstant(n))
                        continue;

                    string suggestion;
                    if (IsMagic(n, out suggestion))
                    {
                        scannedFunction(n, suggestion);
                    }
                }
            }
        }
    }

    public static bool IsMagic(SyntaxNodeOrToken kind, out string suggestion)
    {
        var vdec = kind.Parent.Ancestors().OfType<VariableDeclarationSyntax>().FirstOrDefault();
        if (vdec != null)
        {
            var dec = vdec.Parent as MemberDeclarationSyntax;
            if (dec != null)
            {
                if (!HasConstOrEquivalent(dec))
                {
                    suggestion = "member declaration could be const: " + dec.ToFullString();
                    return true;
                }
            }
            else
            {
                var ldec = vdec.Parent as LocalDeclarationStatementSyntax;
                if (ldec != null)
                {
                    if (!HasConstOrEquivalent(ldec))
                    {
                        suggestion = "local declaration contains at least one non const value: " + ldec.ToFullString();
                        return true;
                    }
                }
            }
        }
        else
        {
            var expr = kind.Parent.Ancestors().OfType<ExpressionSyntax>().FirstOrDefault();
            if (expr != null)
            {
                suggestion = "expression uses a non const value: " + expr.ToFullString();
                return true;
            }
        }

        // TODO: add other cases?

        suggestion = null;
        return false;
    }

    private static bool IsWellKnownConstant(SyntaxNodeOrToken node)
    {
        if (!node.IsToken)
            return false;

        string text = node.AsToken().Text;
        if (text == null)
            return false;

        // note: this is naïve. we also should add 0d, 0f, 0m, etc.
        if (text == "1" || text == "-1" || text == "0")
            return true;

        // ok for '\0' or '\r', etc.
        if (text.Length == 4 && text.StartsWith("'\\") && text.EndsWith("'"))
            return true;

        if (text == "' '")
            return true;

        // TODO add more of these? or make it configurable...

        return false;
    }

    private static bool HasConstOrEquivalent(SyntaxNode node)
    {
        bool hasStatic = false;
        bool hasReadOnly = false;
        foreach (var tok in node.ChildTokens())
        {
            switch (tok.Kind())
            {
                case SyntaxKind.ReadOnlyKeyword:
                    hasReadOnly = true;
                    if (hasStatic)
                        return true;
                    break;

                case SyntaxKind.StaticKeyword:
                    hasStatic = true;
                    if (hasReadOnly)
                        return true;
                    break;

                case SyntaxKind.ConstKeyword:
                    return true;
            }
        }
        return false;
    }

    private static bool CanBeMagic(SyntaxKind kind)
    {
        return kind == SyntaxKind.CharacterLiteralToken ||
            kind == SyntaxKind.NumericLiteralToken ||
            kind == SyntaxKind.StringLiteralToken;
    }
}

如果您运行这个小程序(我还提供了在解决方案或项目中使用它的辅助方法),它将输出以下内容:

 test.cs: (6,20)-(6,22): local declaration contains at least one non const value:         decimal d = 11; // this is not ok

 test.cs: (7,19)-(7,26): local declaration contains at least one non const value:         string s = "magic";

 test.cs: (8,17)-(8,19): expression uses a non const value: i == 29
 test.cs: (11,22)-(11,43): expression uses a non const value: s != "again another magic"
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何查找 C# 项目中的所有硬编码值(解决方案)? 的相关文章

随机推荐

  • 如何删除 GitHub 拉取请求中显示的“Continous-integration/jenkins/pr-merge”和“Continous-integration/jenkins/branch”检查?

    我为 Jenkins 安装了一个插件 它可以分解运行的每个阶段 因此 我不需要额外的两个显示支票 有什么办法可以隐藏它们吗 我能够通过安装以下插件解决这个问题 https github com jenkinsci disable githu
  • 替换字符串中的特定字符

    我想从向量中的字符串中删除特定字符 类似于查找和替换Excel 中的功能 这是我开始的数据 group lt data frame c 12357e 12575e 197e18 e18947 我只从第一列开始 我想通过删除来生成第二列e s
  • SCons 长命令行 TEMPFILE 与 MinGW

    我正在尝试在 Windows 上使用 SCons 和 MinGW 从 gcc 和 gfortran 对象构建共享库 但在最终链接期间命令行太长 超过 18000 个字符 我知道我需要使用临时文件 响应文件 来传递命令行 但我找不到让 SCo
  • OAuth 令牌安全

    据我所知 OAuth 标准对于 OAuth 真正应该如何表现非常宽松 但是 我将各种 OAuth 服务的 OAuth 访问令牌存储在数据库中 如果这些代币被泄露 它们是否可以被第三方使用 即 给定的令牌是否仅绑定到我的 api 和密钥 令牌
  • “g++”不被识别为内部或外部命令、可操作程序或批处理文件。

    我正在尝试使用 C 编译器设置 VScode 通过遵循本教程在此输入链接描述 https medium com jerrygoyal run debug intellisense c c in vscode within 5 minutes
  • 使用Cucumber,有没有一种方法可以在没有界面的情况下登录用户?

    我的绝大多数 Cucumber 功能都需要用户登录 但是 我实际上不需要为每个测试都测试登录功能 我目前正在使用 Devise 进行身份验证 我正在寻找一种使用设备登录用户的方法 而无需填写登录表单 有办法做到这一点吗 我宁愿不必在每次测试
  • kotlin 与 jooq 并手动编写表模型,无需生成代码

    我正在尝试 jOOQ 和 Kotlin 并看过一些教程和文档 它看起来非常好 但如果说 jOOQ 有一个非常烦人的地方就是代码生成 它看起来太复杂了 最终无法维护 我决定创建自己的表模型 类似于 hibernate 的工作原理 我创建了两个
  • 如何使用 A 的值作为映射中的键将 Seq[A] 转换为 Map[Int, A]?

    我有一个Seq包含如下所示的类的对象 class A val key Int 现在我想转换这个Seq to a Map 使用key每个对象的值作为键 对象本身作为值 所以 val seq Seq A val map Map Int A Ho
  • 使用 Python 查找 JSON 中的值

    我之前已经成功地从 JSON 文件解析数据 但现在我想要实现的功能遇到了问题 我有一个 JSON 格式的姓名 身份证号码和生日列表 我想要在 Python 中实现的是能够让用户输入姓名并检索他的身份证号码和出生日期 如果存在 这是我的 JS
  • 同时执行多个批处理文件并监视它们的过程是否完成

    我有一个主批处理文件 它调用多个批处理文件 我希望能够同时执行所有这些批处理文件 全部完成后 我需要在主批处理文件中进行进一步的处理 当我使用 开始 调用多个批处理文件时 我可以同时启动所有批处理文件 但我失去了对它们的跟踪 主批处理文件在
  • 如何在 C# 中启用此计时器?

    我已经开始了 C 课程 但无法让计时器运行 它可能非常简单 我只是在这里错过了一些东西 基本上我有一个按钮来启动和停止交通灯序列 我想要 1 秒的间隔 这是我写的 当我按下开始键时 它没有按预期工作 谢谢 public int counte
  • 需要在 SSRS 订阅上设置日期参数

    我在 SSRS 中有一份报告 它采用单个日期作为参数 我想要的是该报告的订阅使用前两周的星期六作为日期 即 星期一 7 4 将给出星期六 7 16 我如何在订阅中执行此操作 看来我不能在参数中做公式 您必须在报告中设置默认参数值 而不是在订
  • 有没有办法在Python中获取对象的当前引用计数?

    有没有办法在Python中获取对象的当前引用计数 根据Python文档 https docs python org dev library sys html sys getrefcount the sys模块包含一个功能 import sy
  • 清理 Objective-C 代码

    在处理复杂问题时 我发现自己尝试了各种解决方案 尽管尽最大努力保持条理清晰 但代码可能会变得相当混乱 对象可能会被更改并且不再使用 而其他时候我可能会添加代码片段 这些代码片段最终不会被程序使用 但会占用空间和可能的内存 除了仔细阅读程序之
  • install.packages 中的警告:无法移动临时安装

    在 R RStudio 中安装或更新软件包时 我发现了许多与此警告相关的问题 但似乎没有一个问题完全符合我的情况 公司Windows 7系统 因此无管理员权限 无法更改迈克菲防病毒例外列表 R完全安装在用户空间中C Users myname
  • 在Scheme中let和let*有什么区别?

    我正在为 GIMP 编写脚本并使用let 就像我采集的样本一样 但它似乎只是一种 lambda 糖 就像let 为什么它们不同 它们之间有什么区别 它们在变量绑定的顺序上有所不同 例如考虑这个 gt let a 1 b a 2 b 此代码将
  • 没有导出成员

    我是打字稿的新手 我正在使用express js 但遇到以下问题 当我运行服务器时 它显示 routes ts 没有导出的成员 路由器 我一直在寻找但没有成功 这些是我的文件 在我的 src index ts 中 import reflec
  • 用户输入仅需等待 5 秒

    我想在 Turbo C 4 5 编辑器中编写一个简单的 C 程序 这样用户输入只需等待 5 秒 举个例子 include
  • 在 Eclipse 中调试时动态查看画布/位图

    有没有办法在 Eclipse 上调试画布 位图 我想知道当我在特定行设置断点时是否可以查看当前画布 位图的外观 现在可以在调试时查看位图 尽管仅适用于 Android Studio 来自版本 0 8 7 的发行说明 http tools a
  • 如何查找 C# 项目中的所有硬编码值(解决方案)?

    这个问题不仅仅询问硬编码字符串 还询问幻数等 有没有办法找到所有硬编码值即字符串 神奇的数字VS 中的 C 项目 解决方案中没有什么 引发这个问题的是我正在查看的一个项目 我刚刚发现一个字符串值被硬编码重复了 174 次 你能做的就是编程R