如何获取方法中引用的所有属性?

How to get all properties referenced in a method?

假设我们有一些 class 人最终消费:

public class SampleClass
{
    [Obsolete("This property was slain in Moria", false)]
    public double SampleProperty { get; set; }

    [Obsolete("This method was slain in Moria", false)]
    public static void SampleMethod()
    {
    }
}

然后假设有人消费它:

public static double SampleConsumer()
{
    SampleClass.SampleMethod();
    var classy = new SampleClass();
    return classy.SampleProperty;
}

我正在尝试确定 SampleConsumer.

中对过时方法和属性的所有引用

感谢Kris's response to this question.,我已经弄清楚如何获取这些方法总之,它看起来像:

public static void GetMethodReferences(MethodDefinition method)
{
    foreach (var instruction in method.Body.Instructions)
    {
        if (instruction.OpCode == OpCodes.Call)
        {
            MethodReference methodCall = instruction.Operand as MethodReference;  
            // ...

其中 methodCall.CustomAttributes 将包含我们希望检测的过时属性。

我正在尝试为 属性 参考文献完成类似的事情。


到目前为止我尝试过的:

请注意,在 CIL 中,classy.SamplePropertycallvirt 指令表示:

System.Double FoobarNamespace.SampleClass::get_SampleProperty()

我尝试在 GetMethodReferences 中包含 OpCodes.Callvirt,但虚拟 get 方法似乎具有的唯一属性是 CompilerGeneratedAttribute(没有过时的属性)。

接下来我决定深入了解虚拟 get 方法。迭代虚拟方法的指令,注意有一个 ldfld (load field) 指令:

System.Double FoobarNamespace.SampleClass::<SampleProperty>k__BackingField    

我尝试检查它是否有过时的属性:

// for each instruction in the virtual get_SampeProperty()  
    if (instruction.OpCode == OpCodes.Ldfld)
    {
        var fieldDefinition = instruction.Operand as MethodDefinition;
        // check fieldDefinition.Attributes   
        // check fieldDefinition.CustomAttributes   
        // but neither of them have the Obsolete attribute  
        // ...

我认为我实际需要做的是为 SampleProperty 获取 PropertyDefinitionPropertyReference,但我似乎无法弄清楚如何在消费者方法的上下文。

想法?

在 IL 中,方法没有 属性 的概念,只有 属性 的方法概念。我认为塞西尔反映了这一点,所以你不能从 MethodDefinitionPropertyDefinition,但你可以反过来做。

代码可能类似于(未经测试):

MethodDefinition method;

PropertyDefinition property = method.DeclaringType.Properties
    .SingleOrDefault(p => p.GetMethod == method || p.SetMethod == method);

请记住,理论上单个方法可能属于多个属性,但我认为任何理智的编译器都不会这样做。