【问题标题】:FxCop rule to access properties in a specific wayFxCop 规则以特定方式访问属性
【发布时间】:2014-01-03 10:29:42
【问题描述】:

我有一个 Item 类(我无权访问它),它有两种不同的方式来访问 Item 的字段。我想要一个自定义的 FxCop 规则,它优先于另一个。

我可以通过拥有一个项目并直接访问item["fieldname"] 来从特定字段中获取值,这将返回一个字符串。
代码:

public string this[string fieldName]
{
  get
  {
    Assert.ArgumentNotNullOrEmpty(fieldName, "fieldName");
    ID result;
    if (ID.TryParse(fieldName, out result))
      return this[result];
    if ((int) fieldName[0] == 64)
      return this.Fields.GetSpecialField(fieldName);
    Field field = this.Fields[fieldName];
    if (field == null)
      return "";
    else
      return field.Value;
  }
  set
  {
    Assert.ArgumentNotNullOrEmpty(fieldName, "fieldName");
    ID result;
    if (ID.TryParse(fieldName, out result))
    {
      this[result] = value;
    }
    else
    {
      Field field = this.Fields[fieldName];
      if (field == null)
        return;
      field.Value = value;
    }
  }
}

public string this[int index]
{
  get
  {
    Field field = this.Fields[index];
    if (field == null)
      return "";
    else
      return field.Value;
  }
  set
  {
    Field field = this.Fields[index];
    if (field == null)
      return;
    field.Value = value;
  }
}

public string this[ID fieldID]
{
  get
  {
    Assert.ArgumentNotNull((object) fieldID, "fieldID");
    return this.Fields[fieldID].Value;
  }
  set
  {
    Assert.ArgumentNotNull((object) fieldID, "fieldID");
    this.Fields[fieldID].Value = value;
  }
}

或者,我可以像这样访问 Field 属性:item.Fields["Fieldname"].Value
替代代码:

public Field this[ID fieldID]
{
  get
  {
    return new Field(fieldID, this._ownerItem);
  }
}

public Field this[string fieldName]
{
  get
  {
    ID fieldId = TemplateManager.GetFieldId(fieldName, this.TemplateId, this.Database);
    if (fieldId == null)
      return (Field) null;
    else
      return this[fieldId];
  }
}

public Field this[int index]
{
  get
  {
    Field[] fields = this.GetFields();
    if (index < fields.Length && index >= 0)
      return fields[index];
    else
      return (Field) null;
  }
}

这种方法可能会抛出NullReferenceException,例如如果字段名拼写错误。然后Field 对象将是null,因此无法检索该值。

现在,由于第一种方法更安全,我想在使用第二种方法时发出警告。我发现我需要使用

public override ProblemCollection Check(Member member)
{
} 

方法,然后将成员转换为Microsoft.FxCop.Sdk.PropertyNode。但是,从那里开始,我不知道该怎么做,尤其是因为它们最后使用相同的代码(第一个选项调用第二个选项,但是如果字段名拼写错误并且字段为空,则第一个选项将只返回一个空字符串)。

或者,如果这不可能,如果使用第二个选项而不检查字段的空值,我想给出 FxCop 错误。

一些管理细节:我正在使用带有 FxCop 10 的 Visual Studio 2012。

编辑
只是为了进一步澄清,这条规则不应该检查属性本身(即类似Naming.IdentifiersShouldBeCasedCorrectly),而是如何从代码中的其他地方调用它们。

【问题讨论】:

    标签: c# fxcop


    【解决方案1】:

    由于您正在查看这些属性是如何在代码的其他地方使用的,因此您需要使用 BaseIntrospectionRule 的访问者模式支持来查找对有问题的属性的引用。

    只有被分析的程序集的内容会被传递给Check,所以如果包含ItemFieldsCollection 的程序集只是被引用而不是被分析,Item 索引器应该不会引起问题。

    无需深入研究数据流分析(这在很大程度上超出了 Introspector 的范围),您可以通过让访问者遍历所有分析的方法主体并标记 Field.Value getter 的调用来进行非常粗略的近似:

    public override ProblemCollection Check(Member member)
    {
        var method = member as Method;
        if (method != null)
        {
            VisitStatements(method.Body.Statements);
        }
        return Problems;
    }
    
    public override void VisitMethodCall(MethodCall methodCall)
    {
        var memberBinding = methodCall.Callee as MemberBinding;
        if (memberBinding != null)
        {
            var methodCalled = memberBinding.BoundMember as Method;
            if (methodCalled != null)
            {
                if (methodCalled.FullName == "Some.Namespace.Field.get_Value")
                    Problems.Add(new Problem(GetResolution(), methodCall));
            }
        }
        base.VisitMethodCall(methodCall);
    }
    

    更好的近似值还将遍历MethodCall 的第零个Operand,仅当Operand 是对FieldsCollection 索引器的调用时才会引发问题。

    【讨论】:

    • 太好了,似乎很有魅力(至少对于我所做的快速测试而言)。出于某种原因,我没有考虑要引用程序集,因此我不需要担心那么多。
    【解决方案2】:

    为什么不使用 de ObsoleteAttribute

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-14
    • 1970-01-01
    相关资源
    最近更新 更多