প্রতিবিম্ব - বৈশিষ্ট্যের নাম এবং সম্পত্তির মান পান


253

আমার একটি ক্লাস আছে, নাম নামে একটি সম্পত্তি সহ এটি বুক বলতে পারি। সেই সম্পত্তিটির সাথে, এর সাথে আমার একটি বৈশিষ্ট্য যুক্ত রয়েছে।

public class Book
{
    [Author("AuthorName")]
    public string Name
    {
        get; private set; 
    }
}

আমার প্রধান পদ্ধতিতে, আমি প্রতিবিম্বটি ব্যবহার করছি এবং প্রতিটি সম্পত্তির জন্য প্রতিটি বৈশিষ্ট্যের কী মান জোড়া পেতে চাই। সুতরাং এই উদাহরণে, আমি প্রত্যাশা করব গুণকের নামের জন্য "লেখক" এবং বৈশিষ্ট্যটির মানটির জন্য "লেখকনাম"।

প্রশ্ন: আমি প্রতিবিম্বটি ব্যবহার করে কীভাবে আমার বৈশিষ্ট্যগুলির নাম এবং মান পাব?


প্রতিবিম্বের মাধ্যমে আপনি যখন সেই সামগ্রীতে সম্পত্তিটির অ্যাক্সেস করার চেষ্টা করছেন তখন কী ঘটছে, আপনি কি কোথাও আটকে আছেন বা প্রতিবিম্বের জন্য কোড চান
কোবে

উত্তর:


307

উদাহরণগুলির typeof(Book).GetProperties()অ্যারে পেতে ব্যবহার করুন PropertyInfo। তারপরে তাদের কারও কারও এ্যাট্রিবিট টাইপ আছে কিনা তা দেখতে GetCustomAttributes()প্রতিটি ব্যবহার করুন । যদি তারা তা করে থাকে তবে আপনি সম্পত্তির নাম থেকে সম্পত্তিটির নাম এবং বৈশিষ্ট্য থেকে গুণাবলীর মান পেতে পারেন।PropertyInfoAuthor

নির্দিষ্ট বৈশিষ্ট্যযুক্ত বৈশিষ্ট্যগুলির জন্য কোনও ধরণের স্ক্যান করার জন্য এবং অভিধানে ডেটা ফিরিয়ে আনার জন্য এই লাইনের সাথে কিছু রয়েছে (নোট করুন যে এইগুলি রুটিনে প্রেরণ করে আরও গতিশীল করা যেতে পারে):

public static Dictionary<string, string> GetAuthors()
{
    Dictionary<string, string> _dict = new Dictionary<string, string>();

    PropertyInfo[] props = typeof(Book).GetProperties();
    foreach (PropertyInfo prop in props)
    {
        object[] attrs = prop.GetCustomAttributes(true);
        foreach (object attr in attrs)
        {
            AuthorAttribute authAttr = attr as AuthorAttribute;
            if (authAttr != null)
            {
                string propName = prop.Name;
                string auth = authAttr.Name;

                _dict.Add(propName, auth);
            }
        }
    }

    return _dict;
}

16
আমি আশা করছিলাম যে আমাকে বৈশিষ্ট্যটি কাস্ট করতে হবে না।
বিকাশকারীরা

প্রোপ.গেটকাস্টমঅ্যাট্রিবিউটস (সত্য) কেবল একটি বস্তু ফেরায় []। আপনি যদি কাস্ট করতে না চান তবে আপনি এট্রিবিউটের উদাহরণগুলিতে প্রতিচ্ছবি ব্যবহার করতে পারেন।
অ্যাডাম মার্কোইটিজ

এখানে লেখকঅ্যাট্রিবিউট কী? এটি কি এমন শ্রেণি যা অ্যাট্রিবিউট থেকে প্রাপ্ত? @ অ্যাডাম মার্কোভিটস
সারাথ আভানাভ

1
হ্যাঁ. ওপি 'লেখক' নামে একটি কাস্টম বৈশিষ্ট্য ব্যবহার করছে। উদাহরণের জন্য এখানে দেখুন: এমএসডিএন.মাইক্রোসফটকম /en-us/library/sw480ze8.aspx
অ্যাডাম মার্কোভিটস

1
জড়িত প্রতিটি অপারেশনের তুলনায় (নাল চেক এবং স্ট্রিং অ্যাসাইনমেন্ট বাদে) অ্যাট্রিবিউটটি castালাইয়ের পারফরম্যান্স ব্যয় একেবারে তুচ্ছ।
সাইলেন্টসিন

112

অভিধানে কোনও বৈশিষ্ট্যের সমস্ত বৈশিষ্ট্য পেতে এটি ব্যবহার করুন:

typeof(Book)
  .GetProperty("Name")
  .GetCustomAttributes(false) 
  .ToDictionary(a => a.GetType().Name, a => a);

আপনি উত্তরাধিকারী গুণাবলীও অন্তর্ভুক্ত করতে চান কিনা তা থেকে পরিবর্তন falseকরতে trueভুলবেন না।


3
এটি কার্যকরভাবে আদমের সমাধান হিসাবে একই জিনিসটি করে তবে এটি আরও সংক্ষিপ্ত।
ড্যানিয়েল মুর

31
টোড शब्दकोशের পরিবর্তে অভিব্যক্তিতে <অপারেটর অ্যাট্রিবিউ> () যুক্ত করুন যদি আপনার কেবল লেখকের বৈশিষ্ট্য প্রয়োজন এবং ভবিষ্যতের অভিনেত্রী বাদ দিতে চান
অ্যাড্রিয়ান জ্যানেস্কু

2
একই সম্পত্তিতে একই ধরণের দুটি বৈশিষ্ট্য থাকাকালীন এটি কি ব্যতিক্রম করবে না?
কনস্টান্টিন

53

আপনি যদি কেবলমাত্র একটি নির্দিষ্ট অ্যাট্রিবিউট মান চান উদাহরণস্বরূপ প্রদর্শন বৈশিষ্ট্যটি আপনি নিম্নলিখিত কোডটি ব্যবহার করতে পারেন:

var pInfo = typeof(Book).GetProperty("Name")
                             .GetCustomAttribute<DisplayAttribute>();
var name = pInfo.Name;

30

আমি জেনেরিক এক্সটেনশন প্রপার্টি অ্যাট্রিবিউট হেল্পার লিখে একই ধরণের সমস্যাগুলি সমাধান করেছি:

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

public static class AttributeHelper
{
    public static TValue GetPropertyAttributeValue<T, TOut, TAttribute, TValue>(
        Expression<Func<T, TOut>> propertyExpression, 
        Func<TAttribute, TValue> valueSelector) 
        where TAttribute : Attribute
    {
        var expression = (MemberExpression) propertyExpression.Body;
        var propertyInfo = (PropertyInfo) expression.Member;
        var attr = propertyInfo.GetCustomAttributes(typeof(TAttribute), true).FirstOrDefault() as TAttribute;
        return attr != null ? valueSelector(attr) : default(TValue);
    }
}

ব্যবহার:

var author = AttributeHelper.GetPropertyAttributeValue<Book, string, AuthorAttribute, string>(prop => prop.Name, attr => attr.Author);
// author = "AuthorName"

1
আমি কনস্টের থেকে বর্ণনা বৈশিষ্ট্য কীভাবে পেতে পারি Fields?
আমির

1
আপনি একটি পাবেন: ত্রুটি 1775 সদস্যের 'নেমস্পেস.ফিল্ডনেম' উদাহরণের উল্লেখ সহ অ্যাক্সেস করা যাবে না; পরিবর্তে একটি টাইপ নামের সাথে এটি যোগ্যতা অর্জন করুন। আপনার যদি এটির দরকার হয় তবে আমি পরামর্শ দিচ্ছি যে 'কনস্ট' পরিবর্তন করে 'পঠনযোগ্য' করুন।
মিকায়েল এনগ্ভার

1
তার চেয়ে আপনার অনেক বেশি কার্যকর ভোট হওয়া উচিত, সততার সাথে। এটি অনেক ক্ষেত্রে একটি খুব সুন্দর এবং দরকারী উত্তর।
ডেভিড Létourneau

1
ধন্যবাদ @ ডেভিডল্যাটোরনউ! একমাত্র আশা করতে পারেন। দেখে মনে হচ্ছে আপনি এতে কিছুটা সহায়তা করেছেন।
মিকেল এনগরে

:) আপনি কি মনে করেন যে আপনার জেনেরিক পদ্ধতিটি ব্যবহার করে একটি শ্রেণীর জন্য সমস্ত গুণাবলীর মান থাকা এবং প্রতিটি বৈশিষ্ট্যের জন্য বৈশিষ্ট্যের মান নির্ধারণ করা সম্ভব?
ডেভিড Létourneau

21

আপনি ব্যবহার করতে পারেন GetCustomAttributesData()এবং GetCustomAttributes():

var attributeData = typeof(Book).GetProperty("Name").GetCustomAttributesData();
var attributes = typeof(Book).GetProperty("Name").GetCustomAttributes(false);

4
পার্থক্য কি?
প্রাইম বাই ডিজাইন

1
@ প্রাইমবিডিজাইন প্রাক্তনটি প্রয়োগ করা বৈশিষ্ট্যগুলি কীভাবে ইনস্ট্যান্ট করবেন তা আবিষ্কার করেন। পরেরটি আসলে সেই বৈশিষ্ট্যগুলি তাত্ক্ষণিক করে তোলে।
শুভনোমাদ

12

যদি আপনার অর্থ "একটি প্যারামিটার নিয়ে যাওয়া বৈশিষ্ট্যের জন্য, বৈশিষ্ট্য-নাম এবং প্যারামিটার-মান তালিকাভুক্ত করা হয়", তবে CustomAttributeDataএপিআইয়ের মাধ্যমে .NET 4.5 এ এটি আরও সহজ :

using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;

public static class Program
{
    static void Main()
    {
        PropertyInfo prop = typeof(Foo).GetProperty("Bar");
        var vals = GetPropertyAttributes(prop);
        // has: DisplayName = "abc", Browsable = false
    }
    public static Dictionary<string, object> GetPropertyAttributes(PropertyInfo property)
    {
        Dictionary<string, object> attribs = new Dictionary<string, object>();
        // look for attributes that takes one constructor argument
        foreach (CustomAttributeData attribData in property.GetCustomAttributesData()) 
        {

            if(attribData.ConstructorArguments.Count == 1)
            {
                string typeName = attribData.Constructor.DeclaringType.Name;
                if (typeName.EndsWith("Attribute")) typeName = typeName.Substring(0, typeName.Length - 9);
                attribs[typeName] = attribData.ConstructorArguments[0].Value;
            }

        }
        return attribs;
    }
}

class Foo
{
    [DisplayName("abc")]
    [Browsable(false)]
    public string Bar { get; set; }
}


2

উপরের উপরের সর্বাধিক আপত্তিকর উত্তরগুলি অবশ্যই কাজ করে চলেছে, আমি কিছু ক্ষেত্রে কিছুটা ভিন্ন পদ্ধতির ব্যবহারের পরামর্শ দেব।

যদি আপনার শ্রেণীর সর্বদা একই বৈশিষ্ট্যযুক্ত একাধিক বৈশিষ্ট্য থাকে এবং আপনি সেই বৈশিষ্ট্যগুলি একটি অভিধানে বাছাই করতে চান তবে এখানে কীভাবে:

var dict = typeof(Book).GetProperties().ToDictionary(p => p.Name, p => p.GetCustomAttributes(typeof(AuthorName), false).Select(a => (AuthorName)a).FirstOrDefault());

এটি এখনও কাস্ট ব্যবহার করে তবে নিশ্চিত করে যে কাস্ট সর্বদা কাজ করবে কারণ আপনি কেবল "লেখকনাম" টাইপের কাস্টম বৈশিষ্ট্য পাবেন attrib উপরে যদি আপনার একাধিক বৈশিষ্ট্য থাকে তবে উত্তরগুলি একটি কাস্ট ব্যতিক্রম পাবে।


1
public static class PropertyInfoExtensions
{
    public static TValue GetAttributValue<TAttribute, TValue>(this PropertyInfo prop, Func<TAttribute, TValue> value) where TAttribute : Attribute
    {
        var att = prop.GetCustomAttributes(
            typeof(TAttribute), true
            ).FirstOrDefault() as TAttribute;
        if (att != null)
        {
            return value(att);
        }
        return default(TValue);
    }
}

ব্যবহার:

 //get class properties with attribute [AuthorAttribute]
        var props = typeof(Book).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(AuthorAttribute)));
            foreach (var prop in props)
            {
               string value = prop.GetAttributValue((AuthorAttribute a) => a.Name);
            }

বা:

 //get class properties with attribute [AuthorAttribute]
        var props = typeof(Book).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(AuthorAttribute)));
        IList<string> values = props.Select(prop => prop.GetAttributValue((AuthorAttribute a) => a.Name)).Where(attr => attr != null).ToList();

1

এখানে ম্যাক্সলেংথ বা অন্য কোনও বৈশিষ্ট্যটি পেতে আপনি কিছু স্থিতিশীল পদ্ধতি ব্যবহার করতে পারেন।

using System;
using System.Linq;
using System.Reflection;
using System.ComponentModel.DataAnnotations;
using System.Linq.Expressions;

public static class AttributeHelpers {

public static Int32 GetMaxLength<T>(Expression<Func<T,string>> propertyExpression) {
    return GetPropertyAttributeValue<T,string,MaxLengthAttribute,Int32>(propertyExpression,attr => attr.Length);
}

//Optional Extension method
public static Int32 GetMaxLength<T>(this T instance,Expression<Func<T,string>> propertyExpression) {
    return GetMaxLength<T>(propertyExpression);
}


//Required generic method to get any property attribute from any class
public static TValue GetPropertyAttributeValue<T, TOut, TAttribute, TValue>(Expression<Func<T,TOut>> propertyExpression,Func<TAttribute,TValue> valueSelector) where TAttribute : Attribute {
    var expression = (MemberExpression)propertyExpression.Body;
    var propertyInfo = (PropertyInfo)expression.Member;
    var attr = propertyInfo.GetCustomAttributes(typeof(TAttribute),true).FirstOrDefault() as TAttribute;

    if (attr==null) {
        throw new MissingMemberException(typeof(T).Name+"."+propertyInfo.Name,typeof(TAttribute).Name);
    }

    return valueSelector(attr);
}

}

স্থির পদ্ধতি ব্যবহার করে ...

var length = AttributeHelpers.GetMaxLength<Player>(x => x.PlayerName);

বা উদাহরণস্বরূপ extensionচ্ছিক এক্সটেনশন পদ্ধতি ব্যবহার করে ...

var player = new Player();
var length = player.GetMaxLength(x => x.PlayerName);

বা অন্য কোনও অ্যাট্রিবিউটের জন্য সম্পূর্ণ স্থিতিশীল পদ্ধতি ব্যবহার করে (উদাহরণস্বরূপ স্ট্রিংলংথ) ...

var length = AttributeHelpers.GetPropertyAttributeValue<Player,string,StringLengthAttribute,Int32>(prop => prop.PlayerName,attr => attr.MaximumLength);

মিকেল এনগেরের উত্তর থেকে অনুপ্রাণিত।


1

Necromancing।
তাদের এখনও .NET 2.0 বজায় রাখতে হবে বা যারা লিনকিউ ছাড়াই এটি করতে চায় তাদের জন্য:

public static object GetAttribute(System.Reflection.MemberInfo mi, System.Type t)
{
    object[] objs = mi.GetCustomAttributes(t, true);

    if (objs == null || objs.Length < 1)
        return null;

    return objs[0];
}



public static T GetAttribute<T>(System.Reflection.MemberInfo mi)
{
    return (T)GetAttribute(mi, typeof(T));
}


public delegate TResult GetValue_t<in T, out TResult>(T arg1);

public static TValue GetAttributValue<TAttribute, TValue>(System.Reflection.MemberInfo mi, GetValue_t<TAttribute, TValue> value) where TAttribute : System.Attribute
{
    TAttribute[] objAtts = (TAttribute[])mi.GetCustomAttributes(typeof(TAttribute), true);
    TAttribute att = (objAtts == null || objAtts.Length < 1) ? default(TAttribute) : objAtts[0];
    // TAttribute att = (TAttribute)GetAttribute(mi, typeof(TAttribute));

    if (att != null)
    {
        return value(att);
    }
    return default(TValue);
}

ব্যবহারের উদাহরণ:

System.Reflection.FieldInfo fi = t.GetField("PrintBackground");
wkHtmlOptionNameAttribute att = GetAttribute<wkHtmlOptionNameAttribute>(fi);
string name = GetAttributValue<wkHtmlOptionNameAttribute, string>(fi, delegate(wkHtmlOptionNameAttribute a){ return a.Name;});

বা সহজভাবে

string aname = GetAttributValue<wkHtmlOptionNameAttribute, string>(fi, a => a.Name );

0
foreach (var p in model.GetType().GetProperties())
{
   var valueOfDisplay = 
       p.GetCustomAttributesData()
        .Any(a => a.AttributeType.Name == "DisplayNameAttribute") ? 
            p.GetCustomAttribute<DisplayNameAttribute>().DisplayName : 
            p.Name;
}

এই উদাহরণে আমি লেখকের পরিবর্তে ডিসপ্লে-নেম ব্যবহার করেছি কারণ এর সাথে একটি মান সহ প্রদর্শিত করতে 'ডিসপ্লে নাম' নামে একটি ক্ষেত্র রয়েছে।


0

এনাম থেকে বৈশিষ্ট্য পেতে, আমি ব্যবহার করছি:

 public enum ExceptionCodes
 {
  [ExceptionCode(1000)]
  InternalError,
 }

 public static (int code, string message) Translate(ExceptionCodes code)
        {
            return code.GetType()
            .GetField(Enum.GetName(typeof(ExceptionCodes), code))
            .GetCustomAttributes(false).Where((attr) =>
            {
                return (attr is ExceptionCodeAttribute);
            }).Select(customAttr =>
            {
                var attr = (customAttr as ExceptionCodeAttribute);
                return (attr.Code, attr.FriendlyMessage);
            }).FirstOrDefault();
        }

// ব্যবহার

 var _message = Translate(code);

0

এই টুকরা কোডটি রাখার জন্য সঠিক স্থানটি সন্ধান করছেন।

আসুন বলি যে আপনার নীচের সম্পত্তি রয়েছে:

[Display(Name = "Solar Radiation (Average)", ShortName = "SolarRadiationAvg")]
public int SolarRadiationAvgSensorId { get; set; }

এবং আপনি শর্টনাম মান পেতে চান। আপনি করতে পারেন:

((DisplayAttribute)(typeof(SensorsModel).GetProperty(SolarRadiationAvgSensorId).GetCustomAttribute(typeof(DisplayAttribute)))).ShortName;

বা এটিকে সাধারণ করতে:

internal static string GetPropertyAttributeShortName(string propertyName)
{
    return ((DisplayAttribute)(typeof(SensorsModel).GetProperty(propertyName).GetCustomAttribute(typeof(DisplayAttribute)))).ShortName;
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.