कैसे पता लगाएं कि क्या कोई प्रॉपर्टी एक्सपोऑबजेक्ट पर मौजूद है?


188

जावास्क्रिप्ट में आप यह पता लगा सकते हैं कि अपरिभाषित कीवर्ड का उपयोग करके किसी संपत्ति को परिभाषित किया गया है या नहीं:

if( typeof data.myProperty == "undefined" ) ...

आप ExpandoObjectबिना किसी अपवाद के डायनामिक कीवर्ड का उपयोग करके C # में ऐसा कैसे करेंगे ?


5
@ कोडकोड: ध्यान दें कि प्रदर्शित कोड के मूल्य की जांच नहीं करता है data.myProperty; यह जाँच करता है कि क्या typeof data.myPropertyरिटर्न। यह सही है कि data.myPropertyमौजूद हो सकता है और इसे सेट किया जा सकता है undefined, लेकिन उस स्थिति में, typeofइसके अलावा कुछ और लौटाएगा "undefined"। तो यह कोड काम करता है।
अनसमुंड एल्डहॉट्स

जवाबों:


181

MSDN के अनुसार घोषणा से पता चलता है कि यह IDEDIA को लागू कर रहा है:

public sealed class ExpandoObject : IDynamicMetaObjectProvider, 
    IDictionary<string, Object>, ICollection<KeyValuePair<string, Object>>, 
    IEnumerable<KeyValuePair<string, Object>>, IEnumerable, INotifyPropertyChanged

आप यह देखने के लिए उपयोग कर सकते हैं कि क्या कोई सदस्य परिभाषित है:

var expandoObject = ...;
if(((IDictionary<String, object>)expandoObject).ContainsKey("SomeMember")) {
    // expandoObject.SomeMember exists.
}

3
इस चेक को सरल बनाने के लिए, मैंने TryGetValue को ओवरलोड किया है और यह हमेशा सही साबित होता है, अगर संपत्ति को परिभाषित नहीं किया गया था, तो "अपरिभाषित" पर वापसी मूल्य सेट करें। अगर (someObject.someParam! = "अपरिभाषित") ... और यह काम करता है :)
सॉफ्टलिअन

यह भी संभव है :), लेकिन मुझे लगता है कि आपका मतलब ओवरलोडेड के बजाय "ओवरराइड" था।
डायकम

हां। मैं फिर से मैं कहीं और बनाया एक विशेष वस्तु की स्थिरांक मान "अपरिभाषित" बदल दिया है। यह कास्टिंग समस्याओं को रोकता है: पी
सॉफ्टलाइन

1
मेरा मानना ​​है कि यह समाधान अभी भी चालू है; प्रतिबिंब की कीमत के लिए किसी के शब्द को न लें - इसे अपने लिए
परखें

1
@ BlueRaja-DannyPflughoeft हाँ, यह है। कलाकारों के बिना यह सिर्फ एक गतिशील आह्वान होगा, जो आपको आंतरिक मामलों में मिलता है। विशेष रूप से, यह स्पष्ट रूप से लागू किया गया है: github.com/mono/mono/blob/master/mcs/class/dlr/Runtime/…
Dykam

28

एक महत्वपूर्ण अंतर यहां किए जाने के लिए की जरूरत है।

यहां अधिकांश उत्तर एक्सपेंडीओबजेक्ट के लिए विशिष्ट हैं जो प्रश्न में उल्लिखित हैं। लेकिन ASP.Net MVC ViewBag का उपयोग करते समय एक आम उपयोग (और इस सवाल पर उतरने का कारण) है। यह एक कस्टम कार्यान्वयन / डायनामिकऑब्जेक्ट का उपवर्ग है, जो शून्य के लिए किसी भी मनमानी संपत्ति के नाम की जांच करने पर एक अपवाद नहीं फेंकेगा। मान लीजिए कि आप एक संपत्ति घोषित कर सकते हैं जैसे:

@{
    ViewBag.EnableThinger = true;
}

फिर मान लीजिए कि आप इसके मूल्य की जांच करना चाहते हैं, और क्या यह सेट भी है - क्या यह मौजूद है। निम्नलिखित मान्य है,, संकलित कर देगा किसी भी अपवाद फेंक नहीं होगा, और आप सही जवाब देता है:

if (ViewBag.EnableThinger != null && ViewBag.EnableThinger)
{
    // Do some stuff when EnableThinger is true
}

अब EnableThinger की घोषणा से छुटकारा पाएं। समान कोड संकलित करता है और ठीक से चलता है। प्रतिबिंब की कोई जरूरत नहीं।

ViewBag के विपरीत, ExpandoObject फेंक देगा यदि आप उस संपत्ति पर नल की जांच करते हैं जो मौजूद नहीं है। आपकी dynamicवस्तुओं में से MVC ViewBag की gentler कार्यक्षमता प्राप्त करने के लिए , आपको गतिशील के कार्यान्वयन का उपयोग करना होगा जो फेंक नहीं है।

आप बस MVC ViewBag में सटीक कार्यान्वयन का उपयोग कर सकते हैं:

. . .
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
    result = ViewData[binder.Name];
    // since ViewDataDictionary always returns a result even if the key does not exist, always return true
    return true;
}
. . .

https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Mvc/DynamicViewDataDictionary.cs

आप इसे एमवीसी व्यूज में, एमवीसी व्यूज में बंधे हुए देख सकते हैं:

http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/ViewPage.cs

डायनामिक व्यूडैडॉरड के सुशोभित व्यवहार की कुंजी व्यूडैडॉर पर शब्दकोश कार्यान्वयन है, यहां:

public object this[string key]
{
    get
    {
        object value;
        _innerDictionary.TryGetValue(key, out value);
        return value;
    }
    set { _innerDictionary[key] = value; }
}

https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Mvc/ViewDataDictionary.cs

दूसरे शब्दों में, यह हमेशा सभी कुंजी के लिए एक मूल्य देता है, फिर चाहे इसमें कुछ भी हो - यह केवल शून्य है जब कुछ भी नहीं है। लेकिन, ViewDataDictionary के MVC के मॉडल से बंधा होने का बोझ है, इसलिए यह बेहतर है कि एमवीसी व्यू के बाहर उपयोग के लिए सिर्फ सुंदर शब्दकोश भागों को छीन लिया जाए।

यह वास्तव में यहां सभी हिम्मत को पोस्ट करने के लिए बहुत लंबा है - इसमें से अधिकांश सिर्फ IDEDIA को लागू कर रहे हैं - लेकिन यहां एक गतिशील वस्तु (वर्ग DDict) है जो उन गुणों पर शून्य जांच के लिए नहीं फेंकती है जिन्हें घोषित नहीं किया गया है, गिथूब पर:

https://github.com/b9chris/GracefulDynamicDictionary

यदि आप इसे अपने प्रोजेक्ट में NuGet के माध्यम से जोड़ना चाहते हैं, तो इसका नाम GracefulDynamicDictionary है


जब आप प्रतिबिंब का उपयोग नहीं करते हैं तो आपने डायनेमिक कार्ड पर मतदान क्यों किया?
सॉफ्टलिं

तो आप इसे वोट कर सकते हैं क्योंकि यह एक ही समाधान है :)
सॉफ्टलेयन

3
यह निश्चित रूप से एक ही समाधान नहीं है।
क्रिस मोशिनि

"आपको एक समान उपवर्ग बनाने की आवश्यकता होगी जो एक संपत्ति नहीं मिलने पर फेंक नहीं देता है।" => यह है! अरे नहीं यह नहीं है। मेरा समाधान बेहतर है। यह फेंकता है - क्योंकि हम इसे चाहते हैं, और यह भी नहीं फेंक सकता है अगर ट्रिवएक्स का उपयोग किया जाता है;
शीतलयन

1
यह, यह इसलिए है क्योंकि मैं यहाँ हूँ, मैं यह पता नहीं लगा सका कि कुछ कोड (व्यूबैग) क्यों नहीं टूट रहा था। धन्यवाद।
एडम टॉली

11

मैंने हाल ही में एक समान प्रश्न का उत्तर दिया: मैं गतिशील वस्तु के सदस्यों पर कैसे प्रतिबिंबित करूं?

शीघ्र ही, ExpandoObject एकमात्र गतिशील वस्तु नहीं है जो आपको मिल सकती है। प्रतिबिंब स्थैतिक प्रकारों के लिए काम करेगा (वे प्रकार जो ID DynamicsicMetaObjectProvider को लागू नहीं करते हैं)। इस इंटरफ़ेस को लागू करने वाले प्रकारों के लिए, प्रतिबिंब मूल रूप से बेकार है। ExpandoObject के लिए, आप बस जांच सकते हैं कि क्या संपत्ति को अंतर्निहित शब्दकोश में एक कुंजी के रूप में परिभाषित किया गया है। अन्य कार्यान्वयन के लिए, यह चुनौतीपूर्ण हो सकता है और कभी-कभी एकमात्र तरीका अपवादों के साथ काम करना है। जानकारी के लिए, ऊपर दिए गए लिंक का पालन करें।


11

अद्यतन: आप प्रतिनिधियों का उपयोग कर सकते हैं और गतिशील वस्तु संपत्ति से एक मूल्य प्राप्त करने का प्रयास कर सकते हैं यदि यह मौजूद है। यदि कोई संपत्ति नहीं है, तो केवल अपवाद को पकड़ें और झूठे वापस करें।

देखिए, यह मेरे लिए ठीक है:

class Program
{
    static void Main(string[] args)
    {
        dynamic userDynamic = new JsonUser();

        Console.WriteLine(IsPropertyExist(() => userDynamic.first_name));
        Console.WriteLine(IsPropertyExist(() => userDynamic.address));
        Console.WriteLine(IsPropertyExist(() => userDynamic.last_name));
    }

    class JsonUser
    {
        public string first_name { get; set; }
        public string address
        {
            get
            {
                throw new InvalidOperationException("Cannot read property value");
            }
        }
    }

    static bool IsPropertyExist(GetValueDelegate getValueMethod)
    {
        try
        {
            //we're not interesting in the return value. What we need to know is whether an exception occurred or not
            getValueMethod();
            return true;
        }
        catch (RuntimeBinderException)
        {
            // RuntimeBinderException occurred during accessing the property
            // and it means there is no such property         
            return false;
        }
        catch
        {
            //property exists, but an exception occurred during getting of a value
            return true;
        }
    }

    delegate string GetValueDelegate();
}

कोड का आउटपुट निम्न है:

True
True
False

2
@marklam यह अपवाद को पकड़ने के लिए बुरा है जब आप नहीं जानते कि अपवाद का क्या कारण है। जब से हम संभवतः एक क्षेत्र की अनुपस्थिति की उम्मीद करते हैं, हमारे मामलों में यह ठीक है।
अलेक्जेंडर जी

3
यदि आप जानते हैं कि अपवाद का क्या कारण है, तो आपको इसका प्रकार भी पता होना चाहिए, इसलिए पकड़ें (जो भी अपवाद हो) अन्यथा आपका कोड चुपचाप ले जाएगा, भले ही आपको एक अप्रत्याशित अपवाद मिला हो - उदाहरण के लिए OutOfMemoryException।
मार्कलैम

4
आप किसी भी गेट्टर में जा सकते हैं IsPropertyExist। इस उदाहरण में, आप जानते हैं कि कोई एक फेंक सकता है InvalidOperationException। व्यवहार में, आपके पास कोई विचार नहीं है कि किस अपवाद को फेंका जा सकता है। कार्गो पंथ का मुकाबला करने के लिए +1।
piedar

2
यह समाधान अस्वीकार्य है यदि प्रदर्शन महत्वपूर्ण है, उदाहरण के लिए यदि 500+ पुनरावृत्तियों के साथ लूप में उपयोग किया जाता है तो यह कई सेकंड का विलंब हो सकता है। हर बार जब कोई अपवाद पकड़ा जाता है तो स्टैक को अपवाद ऑब्जेक्ट पर कॉपी किया जाना चाहिए
Jim109

1
पुन: प्रदर्शन: डिबगर संलग्न किया जा रहा है और कंसोल। लाइटलाइन धीमी बिट्स हैं। यहां 10,000 पुनरावृत्तियां 200ms से कम (प्रति अपवाद 2 अपवादों के साथ) लेती हैं। बिना किसी अपवाद के एक ही परीक्षण मुट्ठी भर मिलीसेकंड लेता है। इसका मतलब है कि यदि आप इस कोड के उपयोग की उम्मीद करते हैं, तो शायद ही कभी कोई संपत्ति गायब हो, या यदि आप इसे सीमित संख्या में कॉल कर रहे हैं, या परिणाम कैश कर सकते हैं, तो कृपया महसूस करें कि सब कुछ अपनी जगह है और कोई भी नहीं है। -यहां चेतावनी चेताते हैं।
अराजकता

10

मैं एक विस्तार विधि बनाना चाहता था ताकि मैं कुछ ऐसा कर सकूं:

dynamic myDynamicObject;
myDynamicObject.propertyName = "value";

if (myDynamicObject.HasProperty("propertyName"))
{
    //...
}

... लेकिन आप ExpandoObjectC # 5 प्रलेखन ( यहां अधिक जानकारी ) के अनुसार एक्सटेंशन नहीं बना सकते ।

इसलिए मैंने एक क्लास हेल्पर का निर्माण किया:

public static class ExpandoObjectHelper
{
    public static bool HasProperty(ExpandoObject obj, string propertyName)
    {
        return ((IDictionary<String, object>)obj).ContainsKey(propertyName);
    }
}

इसके प्रयेाग के लिए:

// If the 'MyProperty' property exists...
if (ExpandoObjectHelper.HasProperty(obj, "MyProperty"))
{
    ...
}

4
विस्तारक के लिए एक्सटेंशन पर उपयोगी टिप्पणी और लिंक के लिए वोट करें।
रॉबर्टो

1

आप टाइप प्रॉपर सेट के लिए रिफ्लेक्शन का उपयोग क्यों नहीं करना चाहते हैं? ऐशे ही

 dynamic v = new Foo();
 Type t = v.GetType();
 System.Reflection.PropertyInfo[] pInfo =  t.GetProperties();
 if (Array.Find<System.Reflection.PropertyInfo>(pInfo, p => { return p.Name == "PropName"; }).    GetValue(v,  null) != null))
 {
     //PropName initialized
 } 

मुझे यकीन नहीं है कि अगर यह गतिशील रूप से जोड़े गए गुणों को वापस कर देगा, तो मेरा अनुमान है कि यह गतिशील वस्तु के तरीके लौटाता है।
डायकम

1

यह एक्सटेंशन विधि किसी संपत्ति के अस्तित्व की जाँच करती है और फिर मान या अशक्तता लौटाती है। यह उपयोगी है यदि आप नहीं चाहते हैं कि आपके आवेदन अनावश्यक अपवादों को फेंक दें, तो कम से कम आप मदद कर सकते हैं।

    public static object Value(this ExpandoObject expando, string name)
    {
        var expandoDic = (IDictionary<string, object>)expando;
        return expandoDic.ContainsKey(name) ? expandoDic[name] : null;
    }

अगर इस तरह इस्तेमाल किया जा सकता है:

  // lookup is type 'ExpandoObject'
  object value = lookup.Value("MyProperty");

या यदि आपका स्थानीय वैरिएबल 'डायनेमिक' है, तो आपको इसे पहले ExpandoObject पर डालना होगा।

  // lookup is type 'dynamic'
  object value = ((ExpandoObject)lookup).Value("PropertyBeingTested");

1

आपके उपयोग के मामले के आधार पर, यदि अशक्त को अपरिभाषित के रूप में एक ही माना जा सकता है, तो आप अपने एक्सपेंडेओऑब्जेक्ट को एक डायनेमिकजोनऑब्जेक्ट में बदल सकते हैं।

    dynamic x = new System.Web.Helpers.DynamicJsonObject(new ExpandoObject());
    x.a = 1;
    x.b = 2.50;
    Console.WriteLine("a is " + (x.a ?? "undefined"));
    Console.WriteLine("b is " + (x.b ?? "undefined"));
    Console.WriteLine("c is " + (x.c ?? "undefined"));

आउटपुट:

a is 1
b is 2.5
c is undefined


-3

हे लोग सब कुछ के लिए परावर्तन का उपयोग करना बंद कर देते हैं, इसमें बहुत सारे सीपीयू चक्र खर्च होते हैं।

यहाँ समाधान है:

public class DynamicDictionary : DynamicObject
{
    Dictionary<string, object> dictionary = new Dictionary<string, object>();

    public int Count
    {
        get
        {
            return dictionary.Count;
        }
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        string name = binder.Name;

        if (!dictionary.TryGetValue(binder.Name, out result))
            result = "undefined";

        return true;
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        dictionary[binder.Name] = value;
        return true;
    }
}

4
यह दिखाता है कि एक गतिशील वस्तु को कैसे लागू किया जाए, न कि यह कैसे देखा जाए कि एक संपत्ति एक गतिशील वस्तु से बाहर निकलती है।
मैट वॉरेन

आप जाँच कर सकते हैं कि क्या किसी डायनामिक इंस्टेंस के पास विचाराधीन प्रॉपर्टी के लिए एक शून्य जाँच कर संपत्ति है।
ctorx

2
"यह दिखाता है कि एक गतिशील वस्तु को कैसे लागू किया जाए": हाँ वास्तव में यह है। इस प्रश्न का हल है: कोई सामान्य समाधान नहीं है क्योंकि यह कार्यान्वयन पर निर्भर करता है।
शीतलयन

@Softlion नहीं है, समाधान है कि बात यह है कि हम उस राशि का उपयोग बंद करने
nik.shornikov

@Softlion Tryxxx तरीकों का क्या मतलब है? ट्रिपगेट कभी भी गलत नहीं लौटेगा जब यह संपत्ति नहीं ढूंढता है, इसलिए आपको अभी भी परिणाम की जांच करनी होगी। वापसी बेकार है। ट्राईसेट में, यदि कुंजी मौजूद नहीं है, तो यह गलत लौटने के बजाय एक अपवाद फेंक देगा। मुझे समझ में नहीं आता है कि आप इसका उपयोग एक उत्तर के रूप में भी क्यों करेंगे, यदि आप स्वयं यहाँ टिप्पणियों पर लिखते हैं "इस प्रश्न का हल है: कोई सामान्य समाधान नहीं है क्योंकि यह कार्यान्वयन पर निर्भर करता है", यह भी सच नहीं है। वास्तविक समाधान के लिए डायकम के उत्तर को देखें।
pqsk

-5

इसको आजमाओ

public bool PropertyExist(object obj, string propertyName)
{
 return obj.GetType().GetProperty(propertyName) != null;
}

3
यह गतिशील नाम के तहत छिपाई गई वस्तु की संपत्ति के अस्तित्व की जांच करेगा, जो एक कार्यान्वयन विवरण है। क्या आपने पोस्ट करने से पहले वास्तविक समाधान में अपना समाधान सत्यापित किया है? यह बिल्कुल भी काम नहीं करना चाहिए।
सॉफ्टलिं

मैंने वास्तविक समय परिदृश्य में कोड के इस टुकड़े का उपयोग किया है। यह अच्छा काम करता है।
वेंकट

6
मुझे हर समय शून्य देता है, भले ही संपत्ति मौजूद हो।
एटलांटिस

यह बुनियादी वस्तुओं के साथ काम करेगा, लेकिन एक्सपेंडीओबजेक्ट्स के साथ नहीं। डायनेमिक्स, निश्चित नहीं।
जो

1
पुष्टि करने के लिए, यह वस्तुओं के साथ काम नहीं करता हैdynamic (हमेशा रिटर्न null)।
चला गया
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.