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

吉姆吉姆

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

有没有一种方法可以找到所有硬编码的值,即字符串,幻数以及VS中C#项目/解决方案中没有的

提示此问题的原因是我正在查看的项目,我发现硬编码重复了174次字符串值!

西蒙·莫里尔

您可以做的是Roslyn程序,这个小镇上的新人(不是这样)。它使您可以非常轻松地解析C#(或VB.NET)项目。然后,您可以访问检测到的节点并检查您真正要检查的内容。为机器检测魔术文字并不总是像对人类一样容易。例如,1真的是个魔术数字吗?我个人认为不是,但是2个更值得怀疑...

无论如何,这是一个小样本,可以很好地完成我认为的工作,但是可以/应该加以改进,也许是为了调整您的确切业务需求或规则(这很有趣)。

注意Roslyn也可以直接在Visual Studio上下文中使用,因此您可以将此示例转换为所谓的诊断程序(Visual Studio的扩展),它可以帮助您直接在IDE中运行。有一些示例:示例和演练

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"

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何在我的解决方案中找到所有构建事件

来自分类Dev

如何在解决方案中找到哪些项目引用了特定的dll?

来自分类Dev

如何在解决方案中找到哪些项目引用了特定的dll?

来自分类Dev

如何获得解决方案项目中的所有类型?

来自分类Dev

如何在解决方案中设置所有项目以复制本地false

来自分类Dev

如何在C ++中设置多项目解决方案?

来自分类Dev

如何使用roslyn删除c#解决方案中源代码的所有注释?

来自分类Dev

如何在VSPackage中找到解决方案使用哪个版本控制系统

来自分类Dev

如何在R中的一个函数中找到多个解决方案?

来自分类Dev

如何在不加载所有项目的情况下打开Visual Studio解决方案?

来自分类Dev

在TopCoder Arena中找到解决方案

来自分类Dev

如何将解决方案文件中的所有项目更改为 C++17 MSVC?

来自分类Dev

C#逻辑(编码中需要的解决方案)

来自分类Dev

如何遍历所有可能的路径以找到解决方案并选择最佳路径

来自分类Dev

如何在具有其他项目的解决方案中编译单个项目?

来自分类Dev

获取解决方案中的所有启动项目

来自分类Dev

如何获得解决方案中的所有项目名称?

来自分类Dev

如何在 C# 中搜索取决于矩阵中特定值的最佳解决方案

来自分类Dev

如何在C#中找到JSON记录的所有不同键?

来自分类Dev

在MonoDevelop中启动C#解决方案和项目

来自分类Dev

解决方案文件中的C#项目名称

来自分类Dev

如何使一个递归解决方案返回所有可能的解决方案?

来自分类Dev

如何在现有解决方案中将项目添加到源代码管理

来自分类Dev

如何在解决方案中加载/卸载多个项目?

来自分类Dev

如何将C#项目目录传递到解决方案输出目录

来自分类Dev

在单个解决方案中,如何在DNX / ASP.NET 5项目(project.json / xproj)和其他C#项目(csproj)之间共享代码,我有哪些选择?

来自分类Dev

如何获得拓扑排序的所有解决方案

来自分类Dev

如何获得拓扑排序的所有解决方案

来自分类Dev

如何使我的解决方案中的所有项目在共享 assemblyVersion 上具有相同的产品版本?

Related 相关文章

  1. 1

    如何在我的解决方案中找到所有构建事件

  2. 2

    如何在解决方案中找到哪些项目引用了特定的dll?

  3. 3

    如何在解决方案中找到哪些项目引用了特定的dll?

  4. 4

    如何获得解决方案项目中的所有类型?

  5. 5

    如何在解决方案中设置所有项目以复制本地false

  6. 6

    如何在C ++中设置多项目解决方案?

  7. 7

    如何使用roslyn删除c#解决方案中源代码的所有注释?

  8. 8

    如何在VSPackage中找到解决方案使用哪个版本控制系统

  9. 9

    如何在R中的一个函数中找到多个解决方案?

  10. 10

    如何在不加载所有项目的情况下打开Visual Studio解决方案?

  11. 11

    在TopCoder Arena中找到解决方案

  12. 12

    如何将解决方案文件中的所有项目更改为 C++17 MSVC?

  13. 13

    C#逻辑(编码中需要的解决方案)

  14. 14

    如何遍历所有可能的路径以找到解决方案并选择最佳路径

  15. 15

    如何在具有其他项目的解决方案中编译单个项目?

  16. 16

    获取解决方案中的所有启动项目

  17. 17

    如何获得解决方案中的所有项目名称?

  18. 18

    如何在 C# 中搜索取决于矩阵中特定值的最佳解决方案

  19. 19

    如何在C#中找到JSON记录的所有不同键?

  20. 20

    在MonoDevelop中启动C#解决方案和项目

  21. 21

    解决方案文件中的C#项目名称

  22. 22

    如何使一个递归解决方案返回所有可能的解决方案?

  23. 23

    如何在现有解决方案中将项目添加到源代码管理

  24. 24

    如何在解决方案中加载/卸载多个项目?

  25. 25

    如何将C#项目目录传递到解决方案输出目录

  26. 26

    在单个解决方案中,如何在DNX / ASP.NET 5项目(project.json / xproj)和其他C#项目(csproj)之间共享代码,我有哪些选择?

  27. 27

    如何获得拓扑排序的所有解决方案

  28. 28

    如何获得拓扑排序的所有解决方案

  29. 29

    如何使我的解决方案中的所有项目在共享 assemblyVersion 上具有相同的产品版本?

热门标签

归档