问题描述
我希望为我的方法计算对外部数据的访问指标。此外,我想知道我的方法是从哪些对象访问字段和属性的,以确定功能嫉妒代码气味的存在。
对于此示例:
public class DoctorService
{
private List<Doctor> _doctors;
public Doctor FindAvailableDoctor(Daterange timeSpan)
{
foreach (Doctor d in _doctors)
{
foreach(Daterange holiday in d.HolidayDates)
{
d.Test = null;
if (!holiday.OverlapsWith(timeSpan)) return d;
}
}
return null;
}
}
,特别是FindAvailableDoctor方法,我想建立一个包含字段的列表,这些字段将包含Doctor类的HolidayDates和Test属性。我还想知道这两个属性都属于Doctor类(由类名及其名称空间标识)。
我编写了以下代码来完成此操作:
var accessedFields = member.DescendantNodes().OfType<MemberAccessExpressionSyntax>();
foreach (var field in accessedFields)
{
var symbol = semanticModel.GetSymbolInfo(field.Expression).Symbol;
switch(symbol)
{
case ILocalSymbol local:
fields.Add(new CaDETMember { Name = local.Type + "|" + local.Name });
break;
case IPropertySymbol prop:
fields.Add(new CaDETMember { Name = prop.ContainingSymbol + "|" + field.ToString() });
break;
case IParameterSymbol param:
fields.Add(new CaDETMember { Name = param.Type + "|" + field.ToString() });
break;
};
}
,并开始摆弄Symbol API的字段。但是,此解决方案既不干净,我也很肯定会因为非平凡的代码而错过某些边缘情况。
提取一种方法访问的字段和属性名称的更好方法是什么,这样我也可以知道所访问的字段和属性属于哪个类?
编辑:根据杰森的回答,我采用了以下解决方案:
var accessedFields = semanticModel.Getoperation(member).Descendants().OfType<IMemberReferenceOperation>();
foreach (var field in accessedFields)
{
fields.Add(new CaDETMember {Name = field.Member.TodisplayString()});
}
return fields;
解决方法
您的方法实际上是一种非常好的方法,因此不要为此感到难过。第二种方法是使用IOperation API。如果调用SemanticModel.GetOperation()可以得到一棵IOperation树,则可以遍历该树,它表示在代码中各个点处执行的语义操作。特别是,有一个IMemberReferenceOperation指向被引用的成员。像这样:
var memberReferences = semanticModel.GetOperation(methodSyntax).Descendants().OfType<IMemberReferenceOperation>()
将让您查看这些内容,然后从那里获取符号。本地访问也有其他操作。