在运行时使用反射获取ConditionalAttribute的值

本文关键字:获取 ConditionalAttribute 的值 反射 运行时 | 更新日期: 2023-09-27 18:25:16

我正在开发一个库,该库涉及检索给定类型的方法。我一直在使用Type.GetMethods,但我注意到一个问题。假设给定类型中的方法使用ConditionalAttribute,并且此条件的值为false。GetMethods仍然会包括这个方法,但我想忽略它

下面是我尝试的一个简单例子。这个程序是在Debug模式下运行的,所以我想找到一种方法,只调用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是他们定义并传递到我的库中的类型。

在运行时使用反射获取ConditionalAttribute的值

这基本上可以归结为:"我可以通过反射来确定用于编译给定代码的任意条件编译符号吗?"-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);
}