प्रतिबिंब का उपयोग करके ऑब्जेक्ट प्रॉपर्टी सेट करें


323

क्या C # में कोई रास्ता है जहां मैं ऑब्जेक्ट प्रॉपर्टी सेट करने के लिए रिफ्लेक्शन का उपयोग कर सकता हूं?

उदाहरण के लिए:

MyObject obj = new MyObject();
obj.Name = "Value";

मैं obj.Nameप्रतिबिंब के साथ सेट करना चाहता हूं । कुछ इस तरह:

Reflection.SetProperty(obj, "Name") = "Value";

क्या इसे करने का कोई तरीका है?

जवाबों:


391

हाँ, आप उपयोग कर सकते हैं Type.InvokeMember():

using System.Reflection;
MyObject obj = new MyObject();
obj.GetType().InvokeMember("Name",
    BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
    Type.DefaultBinder, obj, "Value");

यदि objकोई संपत्ति नहीं है Name, या इसे सेट नहीं किया जा सकता है, तो यह एक अपवाद फेंक देगा ।

एक अन्य दृष्टिकोण संपत्ति के लिए मेटाडेटा प्राप्त करना है, और फिर इसे सेट करना है। यह आपको संपत्ति के अस्तित्व की जांच करने की अनुमति देगा, और यह सत्यापित कर सकता है कि यह सेट किया जा सकता है:

using System.Reflection;
MyObject obj = new MyObject();
PropertyInfo prop = obj.GetType().GetProperty("Name", BindingFlags.Public | BindingFlags.Instance);
if(null != prop && prop.CanWrite)
{
    prop.SetValue(obj, "Value", null);
}

73
यदि आप उन सभी तारों से निपट नहीं रहे हैं जो आप पहले डेटा को परिवर्तित करना चाहते हैं: var val = Convert.ChangeType(propValue, propInfo.PropertyType); स्रोत: devx.com/vb2themax/Tip/19599
LostNomad311

4
वैकल्पिक रूप से, आप उपयोग कर सकते हैंobj.GetType().GetProperty("Name")?.GetSetMethod()?.Invoke(...)
tecfield

1
इसके CanWrite=Falseप्रकारों के लिए मूल्य निर्धारित करना असंभव है , है ना?
टोडुआ

287

आप भी कर सकते हैं:

Type type = target.GetType();

PropertyInfo prop = type.GetProperty("propertyName");

prop.SetValue (target, propertyValue, null);

जहाँ लक्ष्य वह वस्तु है जहाँ इसकी संपत्ति निर्धारित होगी।


11
मैंने आज यही काम किया है। उपर्युक्त महान काम करता है, जाहिर है कि इसे उपयोग करने का प्रयास करने से पहले अशक्त रूप से अशक्त जांच की जानी चाहिए।
एंटनी स्कॉट

3
@AntonyScott मुझे लगता है कि आप जानना चाहते हैं कि क्या आप गलत संपत्ति जमा कर रहे हैं, तो "चुपचाप विफल" एक बुरे कोर्स की तरह लगता है।
जिह

3
@ अजी मैं आपकी बात देख सकता हूं, लेकिन यह वास्तव में स्थिति पर निर्भर करता है।
एंटनी स्कॉट

94

परावर्तन, मूल रूप से, अर्थात

myObject.GetType().GetProperty(property).SetValue(myObject, "Bob", null);

सुविधा और प्रदर्शन दोनों के संदर्भ में मदद करने के लिए पुस्तकालय हैं; FastMember के साथ उदाहरण के लिए :

var wrapped = ObjectAccessor.Create(obj); 
wrapped[property] = "Bob";

(जो अग्रिम में यह जानने की जरूरत नहीं है कि यह एक संपत्ति बनाम एक संपत्ति है)


वाह, मर्ज से थोड़ा भ्रमित हो गया, लेकिन मुझे आपका जवाब फिर से मिल गया! धन्यवाद, आप एक 'स्वीकार' के लायक हैं, लेकिन चूँकि मेरा धागा विलय हो गया है :( फिर से धन्यवाद!
halfpastfour.am

@MarcGravell, मैं FastMember को देख रहा था और यह काफी दिलचस्प है। क्या हम आपके लिए इस महान दायित्व का उपयोग करने के लिए केवल नश्वर के लिए कहीं न कहीं से शुरू / ट्यूटोरियल कर रहे हैं?
सुधांशु मिश्रा

मैं FastMember द्वारा संपत्ति का प्रकार कैसे प्राप्त कर सकता हूं?
रूहुल्लाह अल्लेम

@Jahan एक्सेसर => GetMembers => सदस्य => प्रकार
मार्क Gravell

बहुत बढ़िया जवाब! एक oneliner के बारे में अच्छी बात यह है कि यह समझने में बहुत तेज़ है, क्योंकि कोई उपयोगकर्ता नाम के चर नहीं हैं जिनके बीच में अपने लिए कोई अर्थ नहीं हो सकता है ..
Bastiaan

27

या आप अपने खुद के एक्सटेंशन क्लास के अंदर मार्क के एक लाइनर को लपेट सकते हैं:

public static class PropertyExtension{       

   public static void SetPropertyValue(this object obj, string propName, object value)
    {
        obj.GetType().GetProperty(propName).SetValue(obj, value, null);
    }
}

और इसे इस तरह से कॉल करें:

myObject.SetPropertyValue("myProperty", "myValue");

अच्छे उपाय के लिए, आइए संपत्ति मूल्य प्राप्त करने के लिए एक विधि जोड़ें:

public static object GetPropertyValue(this object obj, string propName)
{
        return obj.GetType().GetProperty(propName).GetValue (obj, null);
}

14

हाँ, का उपयोग कर System.Reflection:

using System.Reflection;

...

    string prop = "name";
    PropertyInfo pi = myObject.GetType().GetProperty(prop);
    pi.SetValue(myObject, "Bob", null);

13

इस तरह से कुछ का उपयोग करें:

public static class PropertyExtension{       

   public static void SetPropertyValue(this object p_object, string p_propertyName, object value)
   {
    PropertyInfo property = p_object.GetType().GetProperty(p_propertyName);
    property.SetValue(p_object, Convert.ChangeType(value, property.PropertyType), null);
   }
}

या

public static class PropertyExtension{       

   public static void SetPropertyValue(this object p_object, string p_propertyName, object value)
   {
    PropertyInfo property = p_object.GetType().GetProperty(p_propertyName);
    Type t = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
    object safeValue = (value == null) ? null : Convert.ChangeType(value, t);

    property.SetValue(p_object, safeValue, null);
   }
}

2
वह हिस्सा जहां आपको संपत्ति का प्रकार मिलता है और फिर डाली जाती है यह वास्तव में मेरे लिए उपयोगी था। यह एक सम्मोहन की तरह काम करता है। धन्यवाद
मार्क

12

आप खेतों में भी एक सिमिलर तरीके का उपयोग कर सकते हैं:

var obj=new MyObject();
FieldInfo fi = obj.GetType().
  GetField("Name", BindingFlags.NonPublic | BindingFlags.Instance);
fi.SetValue(obj,value)

प्रतिबिंब के साथ सब कुछ एक खुली किताब हो सकती है :) मेरे उदाहरण में हम एक निजी उदाहरण स्तर के क्षेत्र के लिए बाध्य हैं।


8

जब आप किसी ऑब्जेक्ट के गुणों को बड़े पैमाने पर असाइन करना चाहते हैं, तो आप संपत्ति के नामों का उपयोग करके इसे आज़मा सकते हैं:

public static void Assign(this object destination, object source)
    {
        if (destination is IEnumerable && source is IEnumerable)
        {
            var dest_enumerator = (destination as IEnumerable).GetEnumerator();
            var src_enumerator = (source as IEnumerable).GetEnumerator();
            while (dest_enumerator.MoveNext() && src_enumerator.MoveNext())
                dest_enumerator.Current.Assign(src_enumerator.Current);
        }
        else
        {
            var destProperties = destination.GetType().GetProperties();
            foreach (var sourceProperty in source.GetType().GetProperties())
            {
                foreach (var destProperty in destProperties)
                {
                    if (destProperty.Name == sourceProperty.Name && destProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType))
                    {
                        destProperty.SetValue(destination,     sourceProperty.GetValue(source, new object[] { }), new object[] { });
                        break;
            }
        }
    }
}

2
नमस्ते और स्टैक ओवरफ्लो में आपका स्वागत है। कृपया अपने कोड को ठीक से प्रारूपित करें और न केवल इसे अपनी पोस्ट में डंप करें, इससे दूसरों को आपके उत्तर को समझने में मदद मिलेगी।
तीन एफएक्स

0

मैंने अभी एक Nuget पैकेज प्रकाशित किया है जो न केवल पहले स्तर के गुण स्थापित करने की अनुमति देता है, बल्कि किसी भी गहराई में दिए गए ऑब्जेक्ट में नेस्टेड गुण भी रखता है।

यहाँ पैकेज है

किसी वस्तु के गुण का मान उसके मूल से निर्धारित करता है।

ऑब्जेक्ट एक जटिल ऑब्जेक्ट हो सकता है और संपत्ति मल्टी लेवल डीप नेस्टेड संपत्ति हो सकती है या यह सीधे रूट के तहत एक संपत्ति हो सकती है। ObjectWriterप्रॉपर्टी पाथ पैरामीटर का उपयोग कर संपत्ति ढूंढेगा और उसके मूल्य को अपडेट करेगा। प्रॉपर्टी पाथ रूट से अंतिम छोर तक जाने वाली प्रॉपर्टीज का नाम है, जिसे हम सेट करना चाहते हैं, जिसे सीमांत स्ट्रिंग पैरामीटर द्वारा सीमांकित किया गया है।

उपयोग:

ऑब्जेक्ट रूट के तहत सीधे गुण स्थापित करने के लिए:

अर्थात। LineItemवर्ग के पास एक अंतर संपत्ति है जिसे कहा जाता हैItemId

LineItem lineItem = new LineItem();

ObjectWriter.Set(lineItem, "ItemId", 13, delimiter: null);

नेस्टेड संपत्ति को ऑब्जेक्ट रूट के नीचे कई स्तरों पर स्थापित करने के लिए:

अर्थात। Inviteवर्ग के पास एक संपत्ति होती है State, जिसमें एक संपत्ति होती है जिसे Invite(इनवाइट प्रकार का) कहा जाता है Recipient, जिसमें एक संपत्ति होती है, जिसे एक संपत्ति कहा जाता है Id

चीजों को और अधिक जटिल बनाने के लिए, Stateसंपत्ति एक संदर्भ प्रकार नहीं है, यह एक है struct

यहां बताया गया है कि आप एक ही लाइन में ऑब्जेक्ट ट्री के निचले भाग में ईद प्रॉपर्टी ("आउटलुक" को स्ट्रिंग मान पर) कैसे सेट कर सकते हैं।

Invite invite = new Invite();

ObjectWriter.Set(invite, "State_Invite_Recipient_Id", "outlook", delimiter: "_");

0

MarcGravell के सुझाव के आधार पर, मैं का निर्माण किया है निम्नलिखित स्थिर method.The विधि सामान्य रूप से उपयोग करते हुए लक्षित करने के लिए स्रोत ऑब्जेक्ट से सभी मिलान गुण प्रदान करती है FastMember

 public static void DynamicPropertySet(object source, object target)
    {
        //SOURCE
        var src_accessor = TypeAccessor.Create(source.GetType());
        if (src_accessor == null)
        {
            throw new ApplicationException("Could not create accessor!");
        }
        var src_members = src_accessor.GetMembers();
        if (src_members == null)
        {
            throw new ApplicationException("Could not fetch members!");
        }
        var src_class_members = src_members.Where(x => x.Type.IsClass && !x.Type.IsPrimitive);
        var src_class_propNames = src_class_members.Select(x => x.Name);
        var src_propNames = src_members.Except(src_class_members).Select(x => x.Name);

        //TARGET
        var trg_accessor = TypeAccessor.Create(target.GetType());
        if (trg_accessor == null)
        {
            throw new ApplicationException("Could not create accessor!");
        }
        var trg_members = trg_accessor.GetMembers();
        if (trg_members == null)
        {
            throw new ApplicationException("Could not create accessor!");
        }
        var trg_class_members = trg_members.Where(x => x.Type.IsClass && !x.Type.IsPrimitive);
        var trg_class_propNames = trg_class_members.Select(x => x.Name);
        var trg_propNames = trg_members.Except(trg_class_members).Select(x => x.Name);



        var class_propNames = trg_class_propNames.Intersect(src_class_propNames);
        var propNames = trg_propNames.Intersect(src_propNames);

        foreach (var propName in propNames)
        {
            trg_accessor[target, propName] = src_accessor[source, propName];
        }
        foreach (var member in class_propNames)
        {
            var src = src_accessor[source, member];
            var trg = trg_accessor[target, member];
            if (src != null && trg != null)
            {
                DynamicPropertySet(src, trg);
            }
        }
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.