Получить значение 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);
}