#c_sharp #attribute #атрибуты
Есть тестовое консольное приложение.
internal class Program
{
[MyTest("TestDescription")]
static void Main(string[] args)
{
TestSchmest ta = new TestSchmest();
ta.GetSomeThingMethod();
Console.ReadKey();
}
}
internal class TestSchmest
{
public void GetSomeThingMethod([CallerMemberName] string methodName = "")
{
Console.WriteLine("\t - In hell we die!!!");
WhoCalledMe();
Console.WriteLine();
Console.WriteLine("Method \"GetSomeThingMethod\" was called by {0}.", methodName);
// methodName.GetAttribute ???
}
private void WhoCalledMe([CallerMemberName] string methodName = "")
{
Console.WriteLine("\t - For what?!");
Console.WriteLine();
Console.WriteLine("Method \"WhoCalledMe\" was called by {0}.", methodName);
// methodName.GetAttribute ???
}
}
public class MyTestAttribute : Attribute
{
protected string Description;
public MyTestAttribute(string description)
{
Description = description;
}
}
Сначала вызывается метод GetSomeThingMethod класса TestSchmest, который в свою очередь
вызывает метод WhoCalledMe. Можно ли как-то из методов класса TestSchmest узнать, указан
ли атрибут у вызывающего их метода или нет.
Т.е. ta.GetSomeThingMethod() должен показать, что атрибут есть, а WhoCalledMe() что
его нет.
Название класса, в котором вызываются методы (в данном случае Program) может быть
неизвестно.
Ответы
Ответ 1
С помощью класса StackTrace можно получить предыдущий кадр стека, относящийся к вызвавшему методу. Атрибут CallerMemberName при этом не требуется. public void GetSomeThingMethod() { string methodName = ""; MyTestAttribute attribute = null; var st = new StackTrace(); if (st.FrameCount > 1) { var prevFrame = st.GetFrame(1); // получаем кадр стека для вызвавшего метода var caller = prevFrame.GetMethod(); // получаем сам вызвавший метод methodName = caller.Name; var attributes = caller.GetCustomAttributes(typeof(MyTestAttribute), false); if (attributes.Length > 0) attribute = (MyTestAttribute)attributes[0]; } Console.WriteLine("\t - In hell we die!!!"); WhoCalledMe(); Console.WriteLine(); Console.WriteLine("Method \"GetSomeThingMethod\" was called by {0}.", methodName); if (attribute != null) Console.WriteLine("Attribute is present."); } Результат: Method "GetSomeThingMethod" was called by Main. Attribute is present.Ответ 2
Можно получить MethodInfo через класс StackTrace. Учтите, что это достаточно медленный способ, к тому же вам придется отключить inlining, чтобы JIT не вздумал встроить вызываемый / вызывающий метод в тело другого метода - иначе вы просто не увидите метод в stack trace: using System; using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; namespace ConsoleApplication58 { class Program { static void Main(string[] args) { AttributedMethod(); NonAttributedMethod(); } [MyTest("Some Description")] [MethodImpl(MethodImplOptions.NoInlining)] static void AttributedMethod() { CallerDetectionSample(); } [MethodImpl(MethodImplOptions.NoInlining)] static void NonAttributedMethod() { CallerDetectionSample(); } [MethodImpl(MethodImplOptions.NoInlining)] public static void CallerDetectionSample() { // Get call stack StackTrace stackTrace = new StackTrace(); // Get calling method name var attibutes = stackTrace.GetFrame(1).GetMethod().GetCustomAttributes(typeof(MyTestAttribute), true); var description = attibutes.Cast() .Select(a => a.Description) .FirstOrDefault() ?? "no attribute!"; Console.WriteLine(description); } } public class MyTestAttribute : Attribute { public string Description { get; set; } public MyTestAttribute(string description) { Description = description; } } }
Комментариев нет:
Отправить комментарий