简体   繁体   中英

Compile-time detection of accidentally assign a C# property to itself

Visual Studio C# compiler warns about accidentally assigning a variable to itself , but this warning does not apply to C# properties, only variables. As described in this other question .

However, I would really like something similar that can warn me at compile time if I assign a property to itself.

I'm currently using Visual Studio 2013 but I'm ok if the solution works at least in Visual Studio 2015. Also, I don't use third-party commercial plugins like ReSharper or CodeRush so I would prefer a solution that doesn't involve purchasing something, but I'm open to suggestions.

Do you know how could I accomplish this?

Background:

I'm very used to the constructor dependency injection pattern using readonly public "inspection" properties to store the received dependency.

For example, assume a class Foo that depends on an ILogger implementation. The logger instance is provided to the class in the constructor, the constructor checks for nulls and stores the dependency in an instance property called Logger :

public class Foo
{
    public ILogger Logger { get; private set; }

    public Foo(ILogger logger)
    {
        if(logger == null) throw new ArgumentNullException("logger");
        this.Logger = logger;
    }
}

However, I often make the typing mistake of assigning the property to itself instead of the parameter passed to the constructor.

public class Foo
{
    public ILogger Logger { get; private set; }

    public Foo(ILogger logger)
    {
        if(logger == null) throw new ArgumentNullException("logger");
        this.Logger = Logger; // <-- This is wrong. Property assigned to itself.
    }
}

Of course I always end up catching these errors while testing and debugging, but it has bitten me several times already and I don't want to keep wasting time in such a silly mistake anymore.

Any suggestions?

This is the perfect situation for a Live Code Analyzer from VS2015. You could write up a basic analyzer that checks if a property is being assigned to itself and create a error.

Here is a very good tutorial I followed a long time ago to help you get started on how to write one, they are not very hard to do: " C# and Visual Basic - Use Roslyn to Write a Live Code Analyzer for Your API "

UPDATE: I had some free time so I wrote an analyzer up that does it.

[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class SelfAssignmentAnalyzer : DiagnosticAnalyzer
{
    public const string DiagnosticId = "SelfAssignment";

    private static readonly LocalizableString Title = "Do not do self assignment";
    private static readonly LocalizableString MessageFormat = "The variable '{0}' is assigned to itself";
    private static readonly LocalizableString Description = "A variable assignment to itself is likely an indication of a larger error.";
    private const string Category = "Correctness";

    private static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description);

    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }

    public override void Initialize(AnalysisContext context)
    {
        context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.SimpleAssignmentExpression);
    }

    private void AnalyzeNode(SyntaxNodeAnalysisContext context)
    {
        var assignmentExpr = (AssignmentExpressionSyntax)context.Node;

        var right = context.SemanticModel.GetSymbolInfo(assignmentExpr.Right);
        var left = context.SemanticModel.GetSymbolInfo(assignmentExpr.Left);
        if (!right.Equals(left))
            return;

        var diagnostic = Diagnostic.Create(Rule, assignmentExpr.GetLocation(), assignmentExpr.Left.ToString());
        context.ReportDiagnostic(diagnostic);

    }
}

There may be optimizations you could do that could rule situations out without calling GetSymbolInfo (for example checking the text of the left and the right to see that they match) but I leave that as a exercise for you.

EDIT:

The analyzer in action inside Visual Studio 2015:

分析器在行动

Change the way you type the parameters, so the error happens less often.

Parameter first:

   public Foo(ILogger logger)
   { 
   }

Assignment next: copy/paste the parameter twice

   public Foo(ILogger logger)
   { 
       // this.{paste} = {paste};
       this.logger = logger;
   } 

Lastly, correct the misspelt property:

   public Foo(ILogger logger)
   { 
       this.Logger = logger;
   } 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM