طرز کار Attribute در سی شارپ — از صفر تا صد
صفت یا Attribute در زبان #C به تگهای متادیتا گفته میشود که به بخشهای مختلف کد مانند کلاسها، نوعها، متدها و فیلدها انتساب مییابند. شما با استفاده از انعکاس میتوانید تگها را برای تغییر رفتار در برنامهها بررسی کنید. در این راهنما با طرز کار Attribute در سی شارپ و روش استفاده و نوشتن آنها آشنا خواهیم شد.
Attribute چیست؟
صفت یا Attribute به بیان ساده تگهای متادیتا است که برخی اطلاعات را در خود جای داده است.
ساختار آنها شامل نام نوع صفت است که درون براکت و بالاتر از کد تگخورده قرار میگیرد. به مثال زیر توجه کنید:
1[Attribute]
2void Command()
3{
صفتها میتوانند تقریباً به هر چیزی از جمله کلاسها، متدها، فیلدها، استراکتها، نوعها و غیره الصاق یابند. حتی میتوان آنها را به پارامترها داد تا یک ورودی قابل ارزیابی ایجاد کنند، هر چند محدود به نوعهای ابتدایی هستند. امکان تعیین پارامترها با فراخوانی صفت به صورت یک متد مانند زیر وجود دارد:
1[Attribute("name", Test=false, Number=42)]
یک کاربرد رایج نشانهگذاری فیلدها برای سریالسازی است. #C یک تگ داخلی سریالسازی به صورت [Serializable] دارد که از سریالسازی یک کلاس به صورت بایت پشتیبانی میکند و بسیاری از کتابخانههای شخص ثالث نیز وجود دارند که تگهای خاص خود را پیادهسازی میکنند. برای نمونه درایور #C برای MongoDB شامل تگهای زیادی برای سریالسازی برای JSON است و یک تگ خاص نیز برای تفسیر رشته به صورت ID سند دارد.
کاربرد رایج دیگر، متدهای تگگذاری هستند که توسط دستگیره فرمان سطح بالاتری مدیریت میشوند. برای نمونه یک بات دیکسورد (+) یک فهرست از دستورها را ثبت میکند که وقتی فردی پیامی ارسال میکند آنها را مدیریت میکند. به این ترتیب به جای افزودن دستی هر دستور به دستگیره فرمان در هر بار، میتوانید یک تگ [Command("commandname")] به متد بدهید و راهکار ژنریکی که استفاده کنید که آنها را در زمان اجرا به صورت خودکار اضافه میکند.
برای کسب اطلاعات بیشتر در این خصوص میتوانید به مستندات مایکروسافت (+) مراجعه کنید، اما فرایند کار بسیار ساده است.
چطور Attribute بسازیم؟
امکان ساخت Attribute-های سفارشی و اعمال آنها روی کلاسها به سادگی فراهم شده است. تنها کاری که باید بکنید این است که یک کلاس بسازید که از System.Attribute بسط مییابد. همچنین میتوانید صفت را روی این کلاس اضافه و شیوه استفاده از آن را توصیف کنید. برای نمونه میتوانید تعیین کنید که تنها روی کلاسها یا استراکتها اعمال شود..
در ادامه میتوانید فیلدها را تعیین کنید و یک سازنده داشته باشید که پارامترهای ورودی را میگیرد و فیلدها را پر میکند. زمانی که از این صفت استفاده کنید، مانند فراخوانی new Attribute(params) است به جز این که از کلیدواژه new استفاده نمیکنیم.
1[System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct)]
2public class AuthorAttribute : System.Attribute
3{
4 private string name;
5 public double version;
6
7 public AuthorAttribute(string name)
8 {
9 this.name = name;
10 version = 1.0;
11 }
12}
در ادامه توانید از آنها به صورت آزادانه برای تگ زدن کد استفاده کنید. تنها شرط این است که صفت در کدی که تگ میخورد، مورد ارجاع قرار گرفته باشد.
برای دسترسی به صفتها به صورت برنامهنویسیشده باید از «انعکاس» (Reflection) استفاده کنید. Reflection از نظر عملکردی گزینه خوبی محسوب نمیشود، اما در مورد صفتها استفاده از آن مانعی ندارد. میتوانید از Attribute.GetCustomAttributes برای بازگشت یک []Attribute استفاده کنید که نوع کلاس را ارسال میکند:
1System.Attribute.GetCustomAttributes(typeof(className));
اگر بخواهید به همه وهلههای صفتها در اسمبلی دسترسی داشته باشید، میتوانید از ()Assembly.GetExecutingAssembly().GetTypes برای واکشی لیستی از نوعهای اجرایی استفاده کرده و سپس همه صفتهای سفارشی آن نوع را بررسی کنید تا ببینید آیا شامل پارامتر جستجو است یا نه. همچنین میتوانید این لیست را بر اساس نوع کلاسی که صفت به آن تعلق دارد فیلتر کنید.
1var plugins = Assembly.GetExecutingAssembly().GetTypes()
2 .Where(t => t.IsClass
3 && t.BaseType == typeof(BasePlugin)
4 && Attribute.GetCustomAttributes(t).Any((atr) => atr.GetType() == typeof(MyCustomAttribute)))
5 .ToList();
برای دسترسی به پارامترهای صفت، کافی است به صورت مستقیم از کلاس Attribute مانند هر مشخصه عمومی دیگر به آنها دسترسی داشته باشید.