PDA

View Full Version : دریافت نام نمونه ای که از Attribute استفاده کرده



mmbguide
دوشنبه 04 مهر 1401, 23:46 عصر
سلام دوستان

من یک DisplayAttribute سفارشی ایجاد کردم و میخوام اون رو در کلاس های Entity استفاده کنم. به ازای هر property موجود در کلاس entity یکبار کلاس DisplayAttribute اجرا میشه. حالا در این صفت سفارشی من نمیخوام پارامتر ورودی تعریف کنم بلکه میخوام در کدهای نوشته شده در کلاس DisplayAttribute بفهمم که کدام property این صفت را صدا زده. آیا راهی هست که نام property رو بدست بیارم؟

تشکر

ROSTAM2
سه شنبه 05 مهر 1401, 12:32 عصر
سلام.

https://stackoverflow.com/questions/22539591/get-property-name-by-attribute-and-its-value

mmbguide
چهارشنبه 06 مهر 1401, 23:42 عصر
ضمن تشکر. پاسخ صحیح در لینک زیر پیدا شد

https://stackoverflow.com/questions/4606973/how-to-get-name-of-property-which-our-attribute-is-set

mmbguide
جمعه 08 مهر 1401, 22:27 عصر
سلام دوستان

در لینک معرفی شده به یک Attribute با نام CallMemberName اشاره شده که در نتیجه کدهای خودم را بصورت زیر اصلاح کردم:

public cesDisplayAttribute([CallerMemberName] string propertyName = null, Type type = null, bool unique = false)
{
_typeFullName = type?.FullName ?? string.Empty;
_propertyName = propertyName;
_unique = unique;
_displayName = propertyName;
}


در واقع این صفت باید برای یک پارامتر با مقدار Default تعریف بشه و وجود CallMemberName باعث میشه که پارامتر ورودی بصورت خودکار با نام Property که از Attribute سفارشی استفاده کرده مقدار دهی بشه. بنابر این بعد از این کار فقط از attribute سفارشی بدون پارامتر استفاده میکنم و دلیلش هم اینه که در کدهای Atrribute سفارشی با توجه به نام property مقدار معادل اون را به انگلیسی و یا فارسی از بانک میخونم و برمیگردونم و دیگه نیازی نیست که مقدار را برای تمام entityهای یک پروژه تعریف کنم که کار بسیار وقتگیری هم هست.

البته بدین صورت پیاده سازی کردم که اگر مقدار در بانک موجود بود که معادل فارسی و یا انگلیسی اون با توجه به Culture برنامه برگردونده میشه و اگر مقدار وجود نداشت، مقدار جدید داخل بانک ثبت میشه. ابن کار کمک میکنه که مثلا برای تمام propertyهایی که نامشان Id هست تنها یک آیتم در بانک اطلاعاتی ثبت بشه و برای تمام propertyها در تمام برنامه از مقدار آن استفاده خواهد شد. همچنین در صورت نیاز به ایجاد یک نام منحصر بفرد برای یک عنوان با معادل متفاوت، دو پارامتر ورودی باید الزاما مقدار دهی بشه. بدین منظور در زمان ثبت نام property نام کامل کلاس entity به ابتدای نام اضافه خواهد شد که یک کلید منحصر بفرد ایجاد خواهد کرد و میتوان برای این موارد معادل های متفاوتی تعریف کرد.

در نمونه کلاس زیر، بانک اطلاعاتی یک فایل resources.resx هستش که در کنار فایل اصلی برنامه قرار داره و میشه برای تمام زبان ها یک فایل به اون اضافه کرد و یا اگر به بانک اطلاعاتی متصل میشه راه حل های بهتری پیاده سازی کرد. کدهای صفت سفارشی خودم را در زیر قرار میدم شاید بدرد بخوره و اگر هم ایرادی در کد هستش لطفا عنوان کنید (هنوز بررسی و مدیریت همزمانی خواندن و نوشتن در فایل را انجام ندارم). در حال حاضر بررس Culture و انتخاب فایل فارسی و یا انگلیسی پیاده سازی نشده.


using System.Collections;
using System.ComponentModel;
using System.Resources.NetStandard;
using System.Runtime.CompilerServices;


namespace cesEntities
{
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class cesDisplayAttribute : DisplayNameAttribute
{
private string _propertyName { get; set; }
private string _typeFullName { get; set; }
private bool _unique { get; set; }
private string _displayName { get; set; }


public cesDisplayAttribute([CallerMemberName] string propertyName = null, Type type = null, bool unique = false)
{
_typeFullName = type?.FullName ?? string.Empty;
_propertyName = propertyName;
_unique = unique;
_displayName = propertyName;
}


public override string DisplayName
{
get
{
//تعریف آدرس فایل عبارات انگلیسی
string path_en = Path.Combine(Directory.GetCurrentDirectory(), "cesDisplayNames_en.resx");


//نمونه سازی کلاس خواننده اطلاعات از فایل رسورس
ResXResourceReader rr_en = new ResXResourceReader(path_en);
bool check_en = false;

//جستجوی عبارت در فایل انگلیسی
foreach (DictionaryEntry item in rr_en)
{
if (_unique)
{
if (item.Key.ToString() == _typeFullName + "_" + _propertyName)
{
check_en = true;
_displayName = item.Value?.ToString() ?? string.Empty;
return _displayName;
}
}
else
{
if (item.Key.ToString() == _propertyName)
{
check_en = true;
_displayName = item.Value?.ToString() ?? string.Empty;
return _displayName;
}
}
}


//اگر در مرحله قبلی عبارت مورد نظر پیدا نشد به معنای آن است
//که عبارت در آن فایل وجود ندارد و بنابراین باید عبارت جدید
//را در فایل مورد نظر ذخیره کنیم
if (!check_en)
{
ResXResourceWriter rw_en = new ResXResourceWriter(path_en);
var b_en = rr_en.GetEnumerator();


//ابتدا تمام اطلاعات قبلی را در بررسی میکنیم
//و مجددا کلید و مقدار را در فایل ذخیره خواهیم کرد
while (b_en.MoveNext())
{
rw_en.AddResource(b_en.Key.ToString(), b_en.Value?.ToString());
}


//اگر قرار بود عبارت جدید منحصر بفرد باشد باید نام کامل مدل به عنوان
//کلید در نظر گرفته شود و بعد نام پروپرتی به آن اضافه شود در غیر این
//صورت عبارت جدید بدون نام کامل و تنها با نام پروپرتی ذخیره خواهد شد
if (_unique)
{
//برای عبارت انگلیسی که با سه حرف اول
//fld
//شروع می شوند می توان آنها را حذف کرد
rw_en.AddResource(_typeFullName + "_" + _propertyName, _propertyName.Replace("fld",string.Empty));
}
else
{
rw_en.AddResource(_propertyName, _propertyName.Replace("fld", string.Empty));
}


//ایجاد فایل و بستن منابع در سیستم
rw_en.Generate();
rw_en.Close();
rr_en.Close();


//برگرداندن مقدار جدید. البته چون معادل سازی
//برای آن انجام نشده است برای بار اول نام همان
//پروپرتی را برخواهد گرداند
return _propertyName;
}


//اگر هیچ یک از مراحل فوق مقداری را برنگرداند برنامه
//مقدار خالی را به عنوان نتیجه نهایی بر می گرداند
return string.Empty;
}
}
}
}