C# 确定一个方法是否调用另一个包含新语句的程序集中的方法,反之亦然
我想编写一个规则,如果在标记有特定属性的方法调用的任何方法中进行对象分配,则该规则将失败 到目前为止,通过使用C# 确定一个方法是否调用另一个包含新语句的程序集中的方法,反之亦然,c#,.net,fxcop,call-graph,C#,.net,Fxcop,Call Graph,我想编写一个规则,如果在标记有特定属性的方法调用的任何方法中进行对象分配,则该规则将失败 到目前为止,通过使用CallGraph.CallersFor()对调用我的方法的所有方法进行迭代,查看这些父方法中是否有该属性,我已经做到了这一点 这适用于在与要检查的方法相同的程序集中检查父方法,但是在联机阅读时,似乎有一次CallGraph.CallersFor()查看了所有程序集,但现在没有 问题:是否有方法获取调用给定方法的方法列表,包括不同程序集中的方法 备选答案:如果上述方法不可行,如何循环使用
CallGraph.CallersFor()
对调用我的方法的所有方法进行迭代,查看这些父方法中是否有该属性,我已经做到了这一点
这适用于在与要检查的方法相同的程序集中检查父方法,但是在联机阅读时,似乎有一次CallGraph.CallersFor()
查看了所有程序集,但现在没有
问题:是否有方法获取调用给定方法的方法列表,包括不同程序集中的方法
备选答案:如果上述方法不可行,如何循环使用给定方法调用的每个方法,包括不同程序集中的方法
示例:
-----In Assembly A
public class ClassA
{
public MethodA()
{
MethodB();
}
public MethodB()
{
object o = new object(); // Allocation i want to break the rule
// Currently my rule walks up the call tree,
// checking for a calling method with the NoAllocationsAllowed attribute.
// Problem is, because of the different assemblies,
// it can't go from ClassA.MethodA to ClassB.MethodB.
}
}
----In Assembly B
public var ClassAInstance = new ClassA();
public class ClassB
{
[NoAllocationsAllowed] // Attribute that kicks off the rule-checking.
public MethodA()
{
MethodB();
}
public MethodB()
{
ClassAInstance.MethodA();
}
}
我真的不介意规则在哪里报告错误,在这个阶段获得错误就足够了。您是否用这种方式尝试过
StackTrace stackTrace = new StackTrace();
MethodBase methodBase = stackTrace.GetFrame(1).GetMethod();
object [] items = methodBase.GetCustomAttributes(typeof (NoAllocationsAllowed));
if(items.Length > 0)
//do whatever you want!
我通过在FxCop项目中添加所有引用的DLL并使用下面的代码来解决这个问题,该代码手动构建调用树(它还添加了对派生类的调用,以解决我遇到的另一个问题)
公共类CallGraphBuilder:BinaryReadOnlyVisitor
{
公共字典子类型;
公共字典调用者方法;
私有方法_CurrentMethod;
公共调用GraphBuilder()
:base()
{
CallersOfMethod=新字典();
ChildTypes=newdictionary();
}
公共覆盖无效访问方法(方法)
{
_CurrentMethod=方法;
基本访问方法(方法);
}
公共void CreateTypesTree(组装节点组件)
{
foreach(组件类型中的变量类型)
{
if(Type.FullName!=“System.Object”)
{
TypeNode BaseType=Type.BaseType;
if(BaseType!=null&&BaseType.FullName!=“System.Object”)
{
如果(!ChildTypes.ContainsKey(BaseType))
Add(BaseType,newlist());
如果(!ChildTypes[BaseType].包含(类型))
子类型[BaseType]。添加(类型);
}
}
}
}
公共覆盖无效VisitMethodCall(方法调用)
{
方法CalledMethod=(call.Callee作为MemberBinding).BoundMember作为方法;
AddCallerOfMethod(CalledMethod,_CurrentMethod);
Queue MethodsToCheck=new Queue();
MethodsToCheck.Enqueue(称为method);
while(MethodsToCheck.Count!=0)
{
方法CurrentMethod=MethodsToCheck.Dequeue();
if(ChildTypes.ContainsKey(CurrentMethod.DeclaringType))
{
foreach(ChildTypes[CurrentMethod.DeclaringType]中的var-DerivedType)
{
var DerivedCalledMethod=DerivedType.Members.OfType()。其中(M=>MethodHidesMethod(M,CurrentMethod)).SingleOrDefault();
if(DerivedCalledMethod!=null)
{
AddCallerOfMethod(DerivedCalledMethod,CurrentMethod);
方法检查。排队(DerivedCalledMethod);
}
}
}
}
base.VisitMethodCall(调用);
}
私有void AddCallerOfMethod(方法CalledMethod,方法CallingMethod)
{
如果(!CallersOfMethod.ContainsKey(CalledMethod))
Add(CalledMethod,new List());
如果(!CallersOfMethod[CalledMethod].包含(CallingMethod))
CallersOfMethod[CalledMethod].Add(CallingMethod);
}
私有bool方法hidesmethod(方法ChildMethod、方法BaseMethod)
{
while(ChildMethod!=null)
{
if(ChildMethod==BaseMethod)
返回true;
ChildMethod=ChildMethod.OverridedMethod??ChildMethod.HiddenMethod;
}
返回false;
}
}
我不确定我是否真的理解您试图验证的内容。请您提供一个具体的代码示例,说明应该生成违反规则的代码。谢谢您的回答,但我不想在运行时或反射时执行此操作。我想用FxCop执行此操作,它执行静态检查,而不是运行时签入G
public class CallGraphBuilder : BinaryReadOnlyVisitor
{
public Dictionary<TypeNode, List<TypeNode>> ChildTypes;
public Dictionary<Method, List<Method>> CallersOfMethod;
private Method _CurrentMethod;
public CallGraphBuilder()
: base()
{
CallersOfMethod = new Dictionary<Method, List<Method>>();
ChildTypes = new Dictionary<TypeNode, List<TypeNode>>();
}
public override void VisitMethod(Method method)
{
_CurrentMethod = method;
base.VisitMethod(method);
}
public void CreateTypesTree(AssemblyNode Assy)
{
foreach (var Type in Assy.Types)
{
if (Type.FullName != "System.Object")
{
TypeNode BaseType = Type.BaseType;
if (BaseType != null && BaseType.FullName != "System.Object")
{
if (!ChildTypes.ContainsKey(BaseType))
ChildTypes.Add(BaseType, new List<TypeNode>());
if (!ChildTypes[BaseType].Contains(Type))
ChildTypes[BaseType].Add(Type);
}
}
}
}
public override void VisitMethodCall(MethodCall call)
{
Method CalledMethod = (call.Callee as MemberBinding).BoundMember as Method;
AddCallerOfMethod(CalledMethod, _CurrentMethod);
Queue<Method> MethodsToCheck = new Queue<Method>();
MethodsToCheck.Enqueue(CalledMethod);
while (MethodsToCheck.Count != 0)
{
Method CurrentMethod = MethodsToCheck.Dequeue();
if (ChildTypes.ContainsKey(CurrentMethod.DeclaringType))
{
foreach (var DerivedType in ChildTypes[CurrentMethod.DeclaringType])
{
var DerivedCalledMethod = DerivedType.Members.OfType<Method>().Where(M => MethodHidesMethod(M, CurrentMethod)).SingleOrDefault();
if (DerivedCalledMethod != null)
{
AddCallerOfMethod(DerivedCalledMethod, CurrentMethod);
MethodsToCheck.Enqueue(DerivedCalledMethod);
}
}
}
}
base.VisitMethodCall(call);
}
private void AddCallerOfMethod(Method CalledMethod, Method CallingMethod)
{
if (!CallersOfMethod.ContainsKey(CalledMethod))
CallersOfMethod.Add(CalledMethod, new List<Method>());
if (!CallersOfMethod[CalledMethod].Contains(CallingMethod))
CallersOfMethod[CalledMethod].Add(CallingMethod);
}
private bool MethodHidesMethod(Method ChildMethod, Method BaseMethod)
{
while (ChildMethod != null)
{
if (ChildMethod == BaseMethod)
return true;
ChildMethod = ChildMethod.OverriddenMethod ?? ChildMethod.HiddenMethod;
}
return false;
}
}