Compile-time detection accidentally assumes a C # property

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

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

I am currently using Visual Studio 2013, but I am fine if the solution works at least in Visual Studio 2015. In addition, I do not use third-party commercial plugins such as ReSharper or CodeRush, so I would prefer a solution that does not involve buying anything but I am open to suggestions.

Do you know how I could do this?

History:

I’m very used to the constructor embedding pattern , using readonly public β€œcheck” to save the resulting dependency.

For example, suppose a class Foo , which depends on the implementation of ILogger . A logger instance is provided to the constructor class, the constructor checks for zeros 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 an input error when assigning this property to myself, and not to 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 get these errors during testing and debugging, but it has already bitten me several times, and I no longer want to waste time on such a stupid error.

Any suggestions?

+6
source share
2 answers

This is an ideal situation for VS2015 Live Code Analyzer. You can write a basic analyzer that checks whether a property is assigned to itself and creates an error.

Here is a very good tutorial that I followed a long time ago to help you get started on how to write one, they are not very difficult to do: " C # and Visual Basic - use Roslyn to write a code analyzer for your API

UPDATE: I had free time, so I wrote an analyzer that does this.

 [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 manage situations without calling GetSymbolInfo (e.g. checking the text on the left and right to see that they match), but I leave this as an exercise for you.

EDIT:

Analyzer in action inside Visual Studio 2015:

Analyzer in action

+6
source

Change the way you enter the parameters, so the error occurs less frequently.

Parameter first:

  public Foo(ILogger logger) { } 

The purpose of the following: copy / paste the parameter twice

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

Finally, fix the misspelt property:

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

All Articles