C# reflection and finding all references of a Class/Property in my project solution

亡梦爱人 提交于 2020-01-14 03:49:06

问题


I have a class named Test and I instantiated that class in several other classes. Is there any way I could find all references to the Class "Fix" programmatically. I know I could find that with Find All References in VisualStudio but I want to achieve this programmatically for my requirement. Any help, please.

Example: Fix.cs

namespace Testing
{
    public class Fix
    {
        public string fixName = "Name";
    }
}

CodeFix.cs

namespace Testing
{
    public class CodeFix
    {
        private string GetName()
        {
            Fix fix = new Fix();
            return fix.fixName;
        }
    }
}

Now I want to write code to Find All References to a variable "fixName" in my solution (namespace Testing). Is there any way I could achieve this programmatically either for a class or for a variable. I would like to get the result with the fileName and variable referenced code line.

Example:

Result
{
FileName="CodeFix.cs",
Line=return fix.fixName;
}

I am supposed to automate the below scenario for which I need Find All References. I should not use public fields, so When I find a public field like "fixName" I should change the fixName from public to private and then expose the same using a property.

private string fixName;
public string FixName
{
    get { return fixName; }
    set { fixName = value; }
}

so I should change the file codeFix.cs - line return fix.fixName;must be changed with the property name return fix.FixName;.

I have a VSIX project to fix code violation, I need to implement this "automated fix" to avoid using public fields. By any chance Is there a way to get the Visual Studio -> Find All References data?


回答1:


There is a way to use Roslyn for writing unit tests that can check your source code.

For the test project, I'm using xUnit and Buildalyzer (which itself references the Microsoft.CodeAnalysis packages), so that's my test.csproj:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Buildalyzer" Version="0.2.2" />
    <PackageReference Include="Buildalyzer.Workspaces" Version="0.2.2" />
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
    <PackageReference Include="xunit" Version="2.3.1" />
    <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
    <DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
  </ItemGroup>
</Project>

Now there's just a single unit test:

public class UnitTest1
{
    private readonly List<Document> _documents;

    public UnitTest1()
    {
        var projPath = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "..", "CodeFixDemoTests.csproj"));
        AnalyzerManager manager = new AnalyzerManager();
        ProjectAnalyzer analyzer = manager.GetProject(projPath);
        AdhocWorkspace workspace = analyzer.GetWorkspace();
        _documents = new List<Document>();
        foreach (var projectId in workspace.CurrentSolution.ProjectIds)
        {
            var project = workspace.CurrentSolution.GetProject(projectId);
            foreach (var documentId in project.DocumentIds)
            {
                var document = workspace.CurrentSolution.GetDocument(documentId);
                if (document.SupportsSyntaxTree)
                {
                    _documents.Add(document);
                }
            }
        }
    }

    public string _myField;

    [Fact]
    public void NoPublicFields()
    {
        var classes = _documents.Select(doc => new { doc, classes = doc.GetSyntaxRootAsync().Result.DescendantNodes().OfType<ClassDeclarationSyntax>() })
            .SelectMany(doc => doc.classes.Select(@class => new { @class, doc.doc }));

        foreach (var classDeclaration in classes)
        {
            var classFields = classDeclaration.@class.DescendantNodes().OfType<FieldDeclarationSyntax>();
            foreach (var field in classFields)
            {
                var fieldHasPrivateModifier = field.Modifiers.Any(modifier => modifier.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.PrivateKeyword));
                if (!fieldHasPrivateModifier)
                {
                    var errorMessage = $"Public field in class: \"{classDeclaration.@class.Identifier}\", File: {classDeclaration.doc.FilePath}";
                    Assert.True(false, errorMessage);
                }
            }
        }
    }
}

Which gives the following output when run:

(The error that is found is the public string _myField; in the test class itself)

Just make sure to provide it with the correct path to your csproj file and you should be good to go. If you want to get all the errors separate, you could refactor it to use a xUnit Theory instead of a Fact which takes all class declarations as input.



来源:https://stackoverflow.com/questions/48294097/c-sharp-reflection-and-finding-all-references-of-a-class-property-in-my-project

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!