अशक्त संदर्भ प्रकार की जांच करने के लिए .NET प्रतिबिंब का उपयोग कैसे करें


15

C # 8.0 अशक्त संदर्भ प्रकारों का परिचय देता है। यहाँ एक सरल श्रेणी है जिसमें एक अशक्त संपत्ति है:

public class Foo
{
    public String? Bar { get; set; }
}

क्या क्लास प्रॉपर्टी की जांच करने का एक तरीका प्रतिबिंब के माध्यम से एक अशांत संदर्भ प्रकार का उपयोग करता है?


संकलन और आईएल को देखकर, ऐसा लगता है कि यह प्रकार में जोड़ता [NullableContext(2), Nullable((byte) 0)]है ( ) - तो यह है कि क्या जांचना है, लेकिन मुझे यह समझने के लिए अधिक खुदाई करने की आवश्यकता है कि कैसे व्याख्या करें! Foo
मार्क Gravell

4
हां, लेकिन यह तुच्छ नहीं है। सौभाग्य से, यह है प्रलेखित
जेरोइन मोस्टर्ट

ओह समझा; इसलिए string? Xकोई गुण हो जाता है, और string Yहो जाता है [Nullable((byte)2)]साथ [NullableContext(2)]accessors पर
मार्क Gravell

1
यदि किसी प्रकार में सिर्फ नलबल (या गैर-नलिका) होते हैं, तो यह सभी द्वारा दर्शाया जाता है NullableContext। यदि कोई मिश्रण है, तो Nullableइसका उपयोग किया जाता है। NullableContextकोशिश करना और Nullableसभी जगह से बाहर निकलने से बचने के लिए एक अनुकूलन है।
छावनी 7

जवाबों:


11

यह काम करने के लिए प्रकट होता है, कम से कम उन प्रकारों पर, जिनके साथ मैंने इसका परीक्षण किया है।

उत्तीर्ण होने के लिए की जरूरत है PropertyInfoसंपत्ति में आपकी रुचि है के लिए, और यह भी Typeहै कि संपत्ति पर परिभाषित किया गया है ( नहीं एक व्युत्पन्न या पेरेंट प्रकार है - यह सही प्रकार हो गया है):

public static bool IsNullable(Type enclosingType, PropertyInfo property)
{
    if (!enclosingType.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly).Contains(property))
        throw new ArgumentException("enclosingType must be the type which defines property");

    var nullable = property.CustomAttributes
        .FirstOrDefault(x => x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute");
    if (nullable != null && nullable.ConstructorArguments.Count == 1)
    {
        var attributeArgument = nullable.ConstructorArguments[0];
        if (attributeArgument.ArgumentType == typeof(byte[]))
        {
            var args = (ReadOnlyCollection<CustomAttributeTypedArgument>)attributeArgument.Value;
            if (args.Count > 0 && args[0].ArgumentType == typeof(byte))
            {
                return (byte)args[0].Value == 2;
            }
        }
        else if (attributeArgument.ArgumentType == typeof(byte))
        {
            return (byte)attributeArgument.Value == 2;
        }
    }

    var context = enclosingType.CustomAttributes
        .FirstOrDefault(x => x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableContextAttribute");
    if (context != null &&
        context.ConstructorArguments.Count == 1 &&
        context.ConstructorArguments[0].ArgumentType == typeof(byte))
    {
        return (byte)context.ConstructorArguments[0].Value == 2;
    }

    // Couldn't find a suitable attribute
    return false;
}

देखें इस दस्तावेज़ जानकारी के लिए।

सामान्य बात यह है कि या तो संपत्ति में स्वयं इस पर एक [Nullable]विशेषता हो सकती है, या यदि यह संलग्न प्रकार नहीं है तो [NullableContext]विशेषता हो सकती है । हम पहले खोजते हैं [Nullable], फिर यदि हम नहीं पाते हैं तो हम [NullableContext]एनक्लोजिंग प्रकार पर देखते हैं।

कंपाइलर विशेषताओं को असेंबली में एम्बेड कर सकता है, और चूंकि हम एक अलग असेंबली से एक प्रकार देख रहे हैं, इसलिए हमें केवल-प्रतिबिंब लोड करने की आवश्यकता है।

[Nullable]यदि संपत्ति सामान्य है, तो एक सरणी के साथ त्वरित किया जा सकता है। इस मामले में, पहला तत्व वास्तविक संपत्ति का प्रतिनिधित्व करता है (और आगे के तत्व सामान्य तर्कों का प्रतिनिधित्व करते हैं)। [NullableContext]हमेशा एक ही बाइट के साथ त्वरित किया जाता है।

2"शून्य" का अर्थ है। 1का अर्थ है "अशक्त नहीं", और "विस्मृत" का 0अर्थ है।


यह वास्तव में मुश्किल है। मुझे सिर्फ एक उपयोग का मामला मिला है जो इस कोड द्वारा कवर नहीं किया गया है। सार्वजनिक इंटरफ़ेस IBusinessRelation : ICommon {}/ public interface ICommon { string? Name {get;set;} }। यदि मैं IBusinessRelationसंपत्ति के साथ विधि पर कॉल करता हूं तो मैं Nameगलत हो जाता हूं।
gsharp

@gsharp आह, मैंने इसे इंटरफेस, या किसी प्रकार की विरासत के साथ करने की कोशिश नहीं की थी। मैं अनुमान लगा रहा हूं कि यह अपेक्षाकृत आसान फिक्स (आधार इंटरफेस से संदर्भ विशेषताओं को देखें): मैं कोशिश करूंगा और इसे बाद में ठीक
करूंगा

1
कोई बड़ी बात नहीं। मैं सिर्फ इसका उल्लेख करना चाहता था। यह अशक्त सामान मुझे पागल कर रहा है ;-)
gsharp

1
@gsharp इसे देखते हुए, आपको उस प्रकार के इंटरफ़ेस को पास करना होगा जो संपत्ति को परिभाषित करता है - अर्थात ICommon, नहीं IBusinessRelation। प्रत्येक इंटरफ़ेस अपने स्वयं को परिभाषित करता है NullableContext। मैंने अपना उत्तर स्पष्ट कर दिया है, और इसके लिए एक रनटाइम चेक जोड़ा है।
कैंटन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.