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")]
      
    • 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);
              }
          }
      
      • 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();
              }
      
      • DEBUG Result
      • RELEASE Result

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

    • 屬性用來描述在屬性類別中被使用的方式
      • AttributeTargets validOn:包含 Attribute 列舉型別,需設定給所需要的成員
      • Inherited:由衍伸類別繼承並覆寫成員,則為 true;否則為 false
      • AllowMultiple:指出是否可以針對單一程式元素指定所指定屬性的多個執行個體
      • Code
      
          // AttributeUsage 控制,如何應用新定義的特性
          [AttributeUsageAttribute(AttributeTargets.All,  // 應用任何元素
                                   Inherited = false,     // 不繼承到派生類
                                   AllowMultiple = true)] // 允許應用多次
          public class DemoAttribute : Attribute
          {
      
          }
      • 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; }
          }
      • 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 ");
                                  }
                              }
                          }
                      }
                  }
      • Result

沒有留言:

張貼留言