2017年8月10日 星期四

[C#] Attribute, Conditional, Obsolete

  • 目前在 MVC 與 WEB API 中,都有大量地使用 Attribute,需要了解此使用的方法
  • Attribute 
    • 編譯期進行初始化,而不是執行期
    • 用於在運行時傳遞程序中各種元素 (比如類別,方法,結構... 等等)的行為訊息聲明
    • 提供三種預定特性: 
      • AttributeUsage
      • Conditional
      • Obsolete

    • Effective C# 此書中有提到:
      • 推建使用 Conditional attribute (條件特性)
      • 因 #if/#endif 容易被濫用,使得編寫程式難於理解且更難於變更
    • 編譯時會依據指定的值(Debug / Trace),所產生的 IL 比使用 #if/#endif 更有效率
      • Code
      [Conditional("DEBUG")]
      C#
    • Using Conditional
      • Conditional Code:主要在 DEBUG 才會執行時間測試
      public static class ConditionalLib
      {
          static Stopwatch stopwatch = new Stopwatch();
      
          [Conditional("DEBUG")]
          public static void StartLog()
          {
              stopwatch = Stopwatch.StartNew();
          }
      
          [Conditional("DEBUG")]
          public static void StopLog()
          {
              stopwatch.Stop();
              Console.WriteLine("Elapsed:{0} ", stopwatch.Elapsed);
          }
      }
      C#
      • Main Code
      static void Main(string[] args)
      {
          long sum = 0;
      
          Console.WriteLine("Loop 1,000,000");
          ConditionalLib.StartLog();
          for (int i = 0; i <= 1000000; i++ )
          {
              sum += i;
          }
          ConditionalLib.StopLog();
      
          Console.WriteLine("Loop 2,000,000");
          ConditionalLib.StartLog();
          sum = 0;
          for (int i = 0; i <= 2000000; i++)
          {
              sum += i;
          }
          ConditionalLib.StopLog();
      }
      C#
      • DEBUG Result
      • RELEASE Result

    • Obsolete 屬性裝飾的型別或成員,編譯器將會發出警告或錯誤。
      • Obsolete Code
      public class ObsoleteLib
      {
          [Obsolete]
          public void GetUserInfo()
          {
      
          }
      }
      C#
      • Main Code
      static void Main(string[] args)
      {
          ObsoleteLib obsoleteLib = new ObsoleteLib();
          obsoleteLib.GetUserInfo();
      }
      C#
      • Result:都可正常的編譯,但會出現警告訊息
    • 注意:
      • 如果沒有提供錯誤參數,或者如果已經提供了錯誤參數且其值是 false 時,則編譯器將發出警告。
      • Obsolete - error 預設值為 false,可加上 message 資訊
      public class ObsoleteLib
      {
          [Obsolete("Stop maintenance in 2017/08/10", false)]
          public void GetUserName()
          {
      
          }
      }
      C#
      • 若指定錯誤的參數,且該參數擁有 True 值時,編譯器將發出錯誤。
      public class ObsoleteLib
      {
          [Obsolete("Stop maintenance in 2017/08/10", true)]
          public void GetUserName()
          {
      
          }
      }
      C#

    • 屬性用來描述在屬性類別中被使用的方式
      • AttributeTargets validOn:包含 Attribute 列舉型別,需設定給所需要的成員
      • Inherited:由衍伸類別繼承並覆寫成員,則為 true;否則為 false
      • AllowMultiple:指出是否可以針對單一程式元素指定所指定屬性的多個執行個體
      • Code
      // AttributeUsage 控制,如何應用新定義的特性
      [AttributeUsageAttribute(AttributeTargets.All,  // 應用任何元素
                               Inherited = false,     // 不繼承到派生類
                               AllowMultiple = true)] // 允許應用多次
      public class DemoAttribute : Attribute
      {
      
      }
      C#
      • AttributeUsage Code
      [AttributeUsage(AttributeTargets.Property)]
      public class Check : Attribute
      {
          public int MaxLength { get; set; }
      }
      
      public class AttributeLib
      {
          [Check(MaxLength = 10)]
          public string CustomerCode { get; set; }
      }
      C#
      • Main Code:下列有使用 Reflection 讀取 Attribute 的資訊
      using System.Reflection;
      
      // 宣告
      AttributeLib attributeLib = new AttributeLib();
      attributeLib.CustomerCode = "12345678901";
      
      // 取出操作對象的Type (Get the type of the object)
      Type objtype = attributeLib.GetType();
      
      // 利用反射取出成員資訊-Reflection 蠻很耗效能 (Loop through all properties)
      foreach (PropertyInfo p in objtype.GetProperties())
      {
          if (p.Name == "CustomerCode")
          {
              // 取出類別上方的 Attribute
              // 取出類別 Class 中隱含的屬性 0~N Attribute (for every property loop through all attributes)
              foreach (Attribute a in p.GetCustomAttributes(false)) // Reflection.
              {
                  if (a.GetType().Name == "Check")
                  {
                      Check c = (Check)a;
                      // Do the length check and and raise exception accordingly
                      if (attributeLib.CustomerCode.Length > c.MaxLength)
                      {
                          throw new Exception(" Max length issues ");
                      }
                  }
              }
          }
      }
      C#
      • Result

沒有留言:

張貼留言