【问题标题】:Finding all not inheriting C# classes with Roslyn and changing to inheriting from base object (java-like)使用 Roslyn 查找所有不继承 C# 类并更改为从基对象继承(类 java)
【发布时间】:2017-09-18 19:13:35
【问题描述】:

我正在开发一个小型 Roslyn 项目,其中包括更改解析树并将更改写回文件。我从独立的代码分析器开始,并希望将其构建为命令行应用程序。不过,我遇到了挑战。 与: Find classes which derive from a specific base class with Roslyn 部分,主要是: https://github.com/dotnet/roslyn/wiki/Getting-Started-C%23-Syntax-Analysis我创建了这个小项目:

class Program
{
    static void Main(string[] args)
    {
        try
        {
            if (args.Length < 1)
                throw new ArgumentException();
            SyntaxTree tree = CSharpSyntaxTree.ParseText(File.ReadAllText(args[0]));
            var root = (CompilationUnitSyntax) tree.GetRoot();
            var classes = from ClassDeclarationSyntax in root.DescendantNodesAndSelf() select ClassDeclarationSyntax;
            foreach (var c in classes)
            {
                if (/*Not inheriting*/)
                {
                    /*Add inherition*/
                }
            }
            /*Write changes to file*/
        }
        catch (Exception e)
        {
            Console.WriteLine("Fatal error ocured.");
            Console.WriteLine(e.Message);
            Console.WriteLine(e.StackTrace);
        }
    }
}

作为代码状态的 cmets,我需要检查该类是否继承自某些东西(并选择第二个选项)然后更改解析树并最后将其写入文件,现在我很高兴知道如何仅检查“非继承”,尽管也欢迎第二步和第三步的任何指示。解析和更改的文件由路径作为程序参数提供:

if (args.Length < 1)
    throw new ArgumentException();
SyntaxTree tree = CSharpSyntaxTree.ParseText(File.ReadAllText(args[0]));

**解决方案**
在收到的答案的支持下,我想出了工作应用程序。 这是我的代码,可能不完美但有效
class Program
{
    static void Main(string[] args)
    {
        try
        {
            if (args.Length < 1)
                throw new ArgumentException();
            SyntaxTree tree = CSharpSyntaxTree.ParseText(File.ReadAllText(args[0]));
            var root = (CompilationUnitSyntax) tree.GetRoot();
            IdentifierNameSyntax iname = SyntaxFactory.IdentifierName("Object");
            BaseTypeSyntax bts = SyntaxFactory.SimpleBaseType(iname);
            SeparatedSyntaxList<BaseTypeSyntax> ssl = new SeparatedSyntaxList<BaseTypeSyntax>();
            ssl = ssl.Add(bts);
            BaseListSyntax bls = SyntaxFactory.BaseList(ssl);
            bool x = true;
            while(x) //Way to handle all nodes due to impossibility to handle more than one in foreach
            {
                foreach (var c in root.DescendantNodesAndSelf())
                {
                    x = false;
                    var classDeclaration = c as ClassDeclarationSyntax;
                    if (classDeclaration == null)
                        continue;
                    if (classDeclaration.BaseList != null) //Inherits
                        continue;
                    else //Not inherits
                    {
                        root = root.ReplaceNode(classDeclaration, classDeclaration.WithBaseList(bls));
                        x = true;
                        break;
                    }
                }
            }
            if (args.Length > 1) //Write to given file
                using (var sw = new StreamWriter(File.Open(args[1], FileMode.Open)))
                {
                    root.WriteTo(sw);
                }
            else //Overwrite source
                using (var sw = new StreamWriter(File.Open(args[0], FileMode.Open)))
                {
                    root.WriteTo(sw);
                }
        }
        catch (Exception e)
        {
            Console.WriteLine("Fatal error ocured.");
            Console.WriteLine(e.Message);
            Console.WriteLine(e.StackTrace);
        }
    }
}

【问题讨论】:

    标签: c# roslyn-code-analysis


    【解决方案1】:

    ClassDeclarationSyntax 具有包含TypesBaseList。因此,您可以使用这些字段检索有关基类的信息:

            foreach (var c in correctRoot.DescendantNodesAndSelf())
            {
                var classDeclaration = c as ClassDeclarationSyntax;
                if (classDeclaration == null)
                {
                    continue;
                }
                if (classDeclaration.BaseList?.Types.Count > 0)
                {
                    Console.WriteLine("This class has base class or it implements interfaces");
                }
                else
                {
                    /*Add inherition*/
                }
            }
    

    不幸的是,您需要额外的逻辑来区分您的类是基类还是它只是实现了接口。如果您想解决这个问题,您需要使用semantical model 分析基础对象(类/接口)以获取有关相应ISymbol 的信息或尝试找到这些声明syntax tree 中的节点,如果在您的项目/解决方案中定义了此声明。

    另外,如果你想为类添加继承,你需要使用SyntaxFactory.SimpleBaseType(...)SyntaxFactory.BaseList(...) 将新创建的节点设置为BaseList

    【讨论】:

    • 比较BaseListnull 不是更简单吗?从我的实验来看,它也有效。
    • @RobertGrzesiak 好吧,我不知道BaseListnull 之间的比较不起作用的例子,但我还没有找到一些文档解释BaseList 不能当类具有基类或实现接口时为 null。所以我不确定这种比较是否适用于所有情况。
    • 你是完全正确的BaseList 只有当类继承或实现某些东西时才存在。所以BaseList != null据我了解应该可以正常工作。
    • @RobertGrzesiak 抱歉,我之前的评论在我的推理中有一个错误:我不确定当类没有基类或没有实现任何基类时BaseList 总是为空接口。
    猜你喜欢
    • 2015-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多