我有一个 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 错误,如果使用第二个选项而不检查字段的空值。
一些管理细节:我正在使用Visual Studio 2012和FxCop 10。
编辑
为了进一步澄清,此规则不应检查属性本身(即类似于Naming.IdentifiersShouldBeCasedCorrectly
),而应检查如何从代码中的其他地方调用它们。
由于您正在查看如何在代码中的其他地方使用这些属性,因此您需要使用BaseIntrospectionRule
的访问者模式支持来查找对有问题的属性的引用。
只有分析程序集的内容才会传递给Check
,因此,如果仅引用而不是分析包含Item
和FieldsCollection
的程序集,则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
索引器的调用时,才会引发问题。
为什么不使用 de ObsoleteAttribute?