Получить значение ConditionalAttribute во время выполнения, используя отражение

Я работаю над библиотекой, которая включает в себя поиск методов данного типа. Я использую Type.GetMethods, но я заметил проблему. Допустим, что метод в данном типе использует ConditionalAttributeи значение для этого условия ложно. GetMethods по-прежнему будет включать этот метод, но я хотел бы игнорировать его.

Вот простой пример того, что я пытаюсь сделать. Эта программа запускается в режиме отладки, поэтому я хочу найти способ, где только foo() и fooDebug() вызываются, а fooBar() игнорируется.

using System;
using System.Diagnostics;
using System.Reflection;

namespace ConsoleApplication
{
    class ClassA
    {
        public static void foo()
        {
            Console.WriteLine("foo");
        }

        [Conditional("DEBUG")]
        public static void fooDebug()
        {
            Console.WriteLine("fooDebug");
        }

        [Conditional("BAR")]
        public static void fooBar()
        {
            Console.WriteLine("fooBar");
        }
    }

    class Program
    {
    //In this example, I want to find a way where only foo() and fooDebug() are called and fooBar() is ignored, when reflected.
        static void Main(string[] args)
        {
            //Call methods directly.
            //Methods are called/ignored as expected.
            ClassA.foo();//not ignored
            ClassA.fooDebug();//not ignored
            ClassA.fooBar();//ignored

            //Call methods with reflection
            MethodInfo[] methods = typeof(ClassA).GetMethods(BindingFlags.Static | BindingFlags.Public);
            foreach (MethodInfo method in methods)
            {
                //All methods are called, regardless of the ConditionalAttribute.
                method.Invoke(null, null);

                //I figured there would be some workaround like this:
                ConditionalAttribute conditional = 
                Attribute.GetCustomAttribute(method, typeof(ConditionalAttribute)) as ConditionalAttribute;

                if (conditional == null)
                {
                    //The method calls if it has no ConditionalAttribute
                    method.Invoke(null, null);
                }
                else
                {
                    //I can get the string of the condition; but I have no idea how, at runtime, to check if it's defined.
                    string conditionString = conditional.ConditionString;

                    //I also cannnot do a hardcoded (conditionString == "BAR") because the library would not know about BAR
                    bool conditionIsTrue = true;
                    //conditionIsTrue = ??

                    //If the method has a ConditionalAttribute, only call it if the condition is true
                    if (conditionIsTrue)
                    {
                        method.Invoke(null, null);
                    }
                }
            }
        }
    }
}

В конечном счете, я хотел бы знать, какие методы не включают ложные ConditionalAttributes.

РЕДАКТИРОВАТЬ

Эта идея предназначена для библиотеки, которую будут использовать другие, поэтому предположим, что ClassA - это тип, который они определяют и передают в мою библиотеку.

1 ответ

В основном это сводится к следующему: "могу ли я определить с помощью рефлексии произвольные условные символы компиляции, которые использовались для компиляции данного фрагмента кода" - AFAIK, ответ на этот вопрос - "нет".


Примечание: все, что здесь находится, больше не применяется, так как редактирование, которое дает понять, что контекст здесь - библиотека / вызывающая сторона.

Если у вас есть возможность поменять методы (и сделать их закрытыми), то возможно:

partial class Program
{
    static partial void foo();
    static partial void fooDebug();
    static partial void fooBar();

    static partial void foo()
    {
        Console.WriteLine("foo");
    }

#if DEBUG
    static partial void fooDebug()
    {
        Console.WriteLine("fooDebug");
    }
#endif
#if BAR
    static partial void fooBar()
    {
        Console.WriteLine("fooBar");
    }
#endif
    //In this example, I want to find a way where only foo() and fooDebug() are called and fooBar() is ignored, when reflected.
    static void Main(string[] args)
    {
        //Call methods directly.
        //Methods are called/ignored as expected.
        foo();//not ignored
        fooDebug();//not ignored
        fooBar();//ignored

Теперь не реализованные методы не существуют после компиляции, поэтому не будут отображаться в коде отражения. Обратите внимание, что вам нужно использовать BindingFlags.Static | BindingFlags.NonPublic чтобы найти их сейчас, так как они не являются публичными:

MethodInfo[] methods = typeof(Program).GetMethods(BindingFlags.Static | BindingFlags.NonPublic);
foreach (MethodInfo method in methods)
{
    if(method.Name == "Main") continue; // yes, that is lazy
    method.Invoke(null, null);
}
Другие вопросы по тегам