在C#中,当我调用一个方法时,我希望能够检测它是否(或可能)调用具有某个属性的东西。
例如,当调用TheProgram.Run()时,我想知道它会调用一个MyClass.DoTheWork,它有一个属性[IsRegistered],它调用私有方法FormatTheResult(),它也有属性[IsRegistered]。
我已经考虑了一段时间,无法想象它是如何实现的。我在想,就像堆栈跟踪的反转,或者注册具有属性或方面的组件,或者可能依赖于MEF。
这可能吗?
这种检测可能发生在编译时或运行时,但理想情况是在执行带有属性的方法之前。
答案 0 :(得分:2)
模拟框架可以做到这一点。它对行为测试很有用。
例如,给定此设置:
public class Calculator {
private IHelpers _helperMethods;
public Calculator(IHelpers helper) {
_helperMethods = helper;
}
public int Add(int a, int b) {
if (_helperMethods.AboveZero(a) && _helperMethods.AboveZero(b)) {
return a + b;
}
throw new Exception("Argument not above zero");
}
}
public interface IHelpers {
bool AboveZero(int i);
}
使用Moq,您可以验证(通过行为单元测试)在调用IHelpers.AboveZero
方法时调用Add
,如下所示:
[TestMethod]
public void When_Add_Called_Verify_AboveZero_Called_Too() {
// Arrange
var helperMock = new Mock<IHelpers>();
helperMock.Setup(x => x.AboveZero(It.IsAny<int>())).Returns(true);
var calc = new Calculator(helperMock.Object);
// Act
var result = calc.Add(1, 2);
// Assert
helperMock.Verify(x => x.AboveZero(It.IsAny<int>())); // verify that AboveZero was called.
}
虽然这些属性是一个不同的故事..
这是你追求的吗?
(请原谅任何编译错误..这是手工输入的:/)
答案 1 :(得分:1)
你可能正在寻找的是罗斯林。
http://msdn.microsoft.com/en-au/vstudio/roslyn.aspx
您可以使用此方法直接分析语法树,因此对于您所使用的方法,您可以从语法树中访问所有发生的方法调用。然后你可以按照这个并检查被调用的方法是否具有该属性。
是非常复杂的东西,所以我不会为你的特定场景尝试代码示例,但我之前使用它来分析多个solitions并注入代码。
这是非常棒的,这是来自文档的样本。
namespace GettingStartedCS
{
class Program
{
static void Main(string[] args)
{
SyntaxTree tree = SyntaxTree.ParseCompilationUnit(
@"using System;
using System.Collections;
using System.Linq;
using System.Text;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(""Hello, World!"");
}
}
}");
var root = (CompilationUnitSyntax)tree.GetRoot();
var firstMember = root.Members[0];
var helloWorldDeclaration = (NamespaceDeclarationSyntax)firstMember;
var programDeclaration = (TypeDeclarationSyntax)helloWorldDeclaration.Members[0];
var mainDeclaration = (MethodDeclarationSyntax)programDeclaration.Members[0];
var argsParameter = mainDeclaration.ParameterList.Parameters[0];
}
}
}
答案 2 :(得分:0)
Resharper可以满足您的需求。执行菜单命令Resharper - &gt;检查 - &gt;拨出电话,然后无限扩展树节点,直到达到所需的方法。如果你正在使用反射或类似的东西,我猜你运气不好。下面的图片是它如何运作的一个例子。
答案 3 :(得分:0)
这是我发现的方式:
public static IList<MethodBase> GetCalledMethods(MethodBase methodBase)
{
IList<MethodBase> calledMethods = new List<MethodBase>();
var body = methodBase.GetMethodBody();
Module module = Assembly.GetExecutingAssembly().ManifestModule;
byte[] bytes = body.GetILAsByteArray();
using (var stream = new MemoryStream(bytes))
{
long streamLength = stream.Length;
using (var reader = new BinaryReader(stream))
{
while (reader.BaseStream.Position < streamLength)
{
byte instruction = reader.ReadByte();
if (instruction == OpCodes.Call.Value
|| instruction == OpCodes.Callvirt.Value
|| instruction == OpCodes.Newobj.Value)
{
int token = reader.ReadInt32();
var method = module.ResolveMethod(token);
calledMethods.Add(method);
}
}
}
}
return calledMethods;
}