编译时检测意外地将C#属性分配给自身

时间:2016-02-25 16:30:27

标签: c#

Visual Studio C#compiler warns about accidentally assigning a variable to itself,但此警告不适用于C#属性,仅适用于变量。如this other question中所述。

但是,如果我为自己分配一个属性,我真的会喜欢类似的东西,可以在编译时警告我。

我目前正在使用Visual Studio 2013,但如果解决方案至少在Visual Studio 2015中有效,我也没关系。另外,我不使用像ReSharper或CodeRush这样的第三方商业插件,所以我更喜欢一个解决方案不涉及购买东西,但我愿意接受建议。

你知道我怎么能做到这一点?

背景:

我非常习惯constructor dependency injection模式,使用readonly public "inspection" properties来存储收到的依赖项。

例如,假设一个依赖于Foo实现的类ILoggerlogger实例在构造函数中提供给类,构造函数检查空值并将依赖项存储在名为Logger的实例属性中:

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

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

但是,我经常输入错误,将属性赋给自己而不是传递给构造函数的参数。

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.
    }
}

当然,我总是在测试和调试时总是抓住这些错误,但它已经咬过我几次了,我不想再浪费时间在这样一个愚蠢的错误中了。

有什么建议吗?

2 个答案:

答案 0 :(得分:6)

这是VS2015实时代码分析器的完美情况。您可以编写一个基本分析器来检查属性是否被分配给自己并创建错误。

这是一篇非常好的教程,我很久以前就帮助你开始学习如何编写一篇,但它们并不是很难做到:“C# and Visual Basic - Use Roslyn to Write a Live Code Analyzer for Your API

更新:我有一些空闲时间,所以我写了一个分析器就可以了。

[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);

    }
}

您可以进行优化,可以在不调用GetSymbolInfo的情况下排除情况(例如检查左侧和右侧的文本以查看它们是否匹配),但我将其作为练习留给您。

编辑:

Visual Studio 2015中的分析器:

Analyzer in action

答案 1 :(得分:0)

更改键入参数的方式,以便更少发生错误。

参数优先:

   public Foo(ILogger logger)
   { 
   }

下一步分配:复制/粘贴参数两次

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

最后,纠正拼错属性:

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