#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; } } }
Комментариев нет:
Отправить комментарий