c# - क्या 'पठनीय' संशोधक किसी क्षेत्र की छिपी हुई प्रति बनाता है?



struct value-type (1)

MutableSlab और MutableSlab कार्यान्वयन के बीच एकमात्र अंतर handle फ़ील्ड पर आसानी से लागू किया गया है:

using System;
using System.Runtime.InteropServices;

public class Program
{
    class MutableSlab : IDisposable
    {
        private GCHandle handle;

        public MutableSlab()
        {
            this.handle = GCHandle.Alloc(new byte[256], GCHandleType.Pinned);
        }

        public bool IsAllocated => this.handle.IsAllocated;

        public void Dispose()
        {
            this.handle.Free();
        }
    }

    class ImmutableSlab : IDisposable
    {
        private readonly GCHandle handle;

        public ImmutableSlab()
        {
            this.handle = GCHandle.Alloc(new byte[256], GCHandleType.Pinned);
        }

        public bool IsAllocated => this.handle.IsAllocated;

        public void Dispose()
        {
            this.handle.Free();
        }
    }

    public static void Main()
    {
        var mutableSlab = new MutableSlab();
        var immutableSlab = new ImmutableSlab();

        mutableSlab.Dispose();
        immutableSlab.Dispose();

        Console.WriteLine($"{nameof(mutableSlab)}.handle.IsAllocated = {mutableSlab.IsAllocated}");
        Console.WriteLine($"{nameof(immutableSlab)}.handle.IsAllocated = {immutableSlab.IsAllocated}");
    }
}

लेकिन वे अलग परिणाम देते हैं:

mutableSlab.handle.IsAllocated = False
immutableSlab.handle.IsAllocated = True

GCHandle एक उत्परिवर्तनीय संरचना है और जब आप इसे कॉपी करते हैं तो यह बिलकुल उसी तरह व्यवहार करता है जैसे immutableSlab स्लैब के साथ।

क्या आसानी से संशोधक एक क्षेत्र की एक छिपी प्रतिलिपि बनाता है? क्या इसका मतलब है कि यह केवल एक संकलन-समय की जांच नहीं है? मुझे इस व्यवहार के बारे में here कुछ भी नहीं मिला। क्या यह व्यवहार प्रलेखित है?


क्या आसानी से संशोधक एक क्षेत्र की एक छिपी प्रतिलिपि बनाता है?

एक विधि या संपत्ति को एक नियमित संरचना प्रकार (केवल कंस्ट्रक्टर या स्थिर कंस्ट्रक्टर के बाहर) के फ़ील्ड पर कॉल करना, पहले फ़ील्ड की प्रतिलिपि बनाता है, हाँ। ऐसा इसलिए है क्योंकि कंपाइलर को पता नहीं है कि प्रॉपर्टी या मेथड एक्सेस आपके द्वारा कॉल की गई वैल्यू को संशोधित करेगा या नहीं।

C # 5 ECMA विनिर्देश से :

धारा 12.7.5.1 (सदस्य पहुंच, सामान्य)

यह सदस्य एक्सेस को वर्गीकृत करता है, जिसमें शामिल हैं:

  • यदि मैं एक स्थिर क्षेत्र की पहचान करता हूं:
    • यदि क्षेत्र आसानी से पढ़ा जाता है और संदर्भ वर्ग या संरचना के स्थिर निर्माणकर्ता के बाहर होता है जिसमें फ़ील्ड घोषित किया जाता है, तो परिणाम एक मूल्य है, अर्थात स्थिर क्षेत्र I का मूल्य ई।
    • अन्यथा, परिणाम एक चर है, अर्थात् स्थिर क्षेत्र I में ई।

तथा:

  • यदि T एक संरचना-प्रकार है और मैं उस संरचना-प्रकार के उदाहरण क्षेत्र की पहचान करता हूं:
    • यदि ई एक मान है, या यदि फ़ील्ड को आसानी से पढ़ा जाता है और संदर्भ उस संरचना के एक इंस्टेंस कंस्ट्रक्टर के बाहर होता है जिसमें फ़ील्ड घोषित किया जाता है, तो परिणाम एक मूल्य होता है, अर्थात द्वारा दिए गए स्ट्रक्चर इंस्टेंस में फ़ील्ड का मान ई
    • अन्यथा, परिणाम एक चर है, अर्थात् ई द्वारा दिए गए संरचनात्मक उदाहरण में फ़ील्ड I।

मुझे यकीन नहीं है कि इंस्टेंस फील्ड पार्ट विशेष रूप से स्ट्रक्चर टाइप्स को संदर्भित क्यों करता है, लेकिन स्टैटिक फील्ड पार्ट नहीं है। महत्वपूर्ण हिस्सा यह है कि क्या अभिव्यक्ति को एक चर या मूल्य के रूप में वर्गीकृत किया गया है। यह तो फ़ंक्शन सदस्य आह्वान में महत्वपूर्ण है ...

धारा 12.6.6.1 (समारोह सदस्य आह्वान, सामान्य)

किसी फ़ंक्शन सदस्य मंगलाचरण की रन-टाइम प्रोसेसिंग में निम्न चरण होते हैं, जहाँ M फ़ंक्शन सदस्य होता है और, यदि M एक उदाहरण सदस्य है, तो E उदाहरण अभिव्यक्ति है:

[...]

  • अन्यथा, यदि E का प्रकार एक मान-प्रकार V है, और M को V में घोषित या ओवरराइड किया गया है:
    • [...]
    • यदि E को एक चर के रूप में वर्गीकृत नहीं किया जाता है, तो E का एक अस्थायी स्थानीय चर बनाया जाता है और E का मान उस चर को सौंपा जाता है। ई तो उस अस्थायी स्थानीय चर के संदर्भ के रूप में पुनर्वर्गीकृत है। अस्थायी चर एम के भीतर इस रूप में सुलभ है, लेकिन किसी अन्य तरीके से नहीं। इस प्रकार, केवल जब ई एक सच्चा चर है, तो कॉल करने वाले के लिए यह संभव है कि एम उस पर होने वाले परिवर्तनों का निरीक्षण कर सके।

यहाँ एक स्व-निहित उदाहरण दिया गया है:

using System;
using System.Globalization;

struct Counter
{
    private int count;

    public int IncrementedCount => ++count;
}

class Test
{
    static readonly Counter readOnlyCounter;
    static Counter readWriteCounter;

    static void Main()
    {
        Console.WriteLine(readOnlyCounter.IncrementedCount);  // 1
        Console.WriteLine(readOnlyCounter.IncrementedCount);  // 1
        Console.WriteLine(readOnlyCounter.IncrementedCount);  // 1

        Console.WriteLine(readWriteCounter.IncrementedCount); // 1
        Console.WriteLine(readWriteCounter.IncrementedCount); // 2
        Console.WriteLine(readWriteCounter.IncrementedCount); // 3
    }
}

यहाँ readOnlyCounter.IncrementedCount लिए कॉल करने के लिए IL है।

ldsfld     valuetype Counter Test::readOnlyCounter
stloc.0
ldloca.s   V_0
call       instance int32 Counter::get_IncrementedCount()

वह स्टैक पर फ़ील्ड मान की प्रतिलिपि बनाता है, फिर प्रॉपर्टी को कॉल करता है ... इसलिए फ़ील्ड का मान बदलता नहीं है; यह कॉपी के भीतर बढ़ रही count है।

पठन-पाठन क्षेत्र के लिए IL से तुलना करें:

ldsflda    valuetype Counter Test::readWriteCounter
call       instance int32 Counter::get_IncrementedCount()

यह कॉल सीधे फ़ील्ड पर करता है, इसलिए फ़ील्ड मान संपत्ति के भीतर बदल जाता है।

प्रतिलिपि बड़ी होने पर अक्षम हो सकती है जब सदस्य बड़ा होता है और सदस्य इसे म्यूट नहीं करता है। यही कारण है कि C # 7.2 और इसके बाद के संस्करण में, एक संरचना में आसानी से लागू किया जा सकता है। यहाँ एक और उदाहरण है:

using System;
using System.Globalization;

readonly struct ReadOnlyStruct
{
    public void NoOp() {}
}

class Test
{
    static readonly ReadOnlyStruct field1;
    static ReadOnlyStruct field2;

    static void Main()
    {
        field1.NoOp();
        field2.NoOp();
    }
}

संरचना पर आसानी से संशोधक के साथ, field1.NoOp() कॉल कॉपी नहीं बनाता है। यदि आप आसानी से readonly संशोधक को हटा देते हैं, तो आप देखेंगे कि यह एक प्रतिलिपि बनाता है जैसे कि यह readOnlyCounter.IncrementedCount में किया गया था। readOnlyCounter.IncrementedCount किया गया।

मेरे पास codeblog.jonskeet.uk/2014/07/16/… एक codeblog.jonskeet.uk/2014/07/16/… जो मैंने लिखा है कि यह पाया गया कि आसानी से खेतों में काम कर रहे थे, नोडा टाइम में प्रदर्शन के मुद्दे। सौभाग्य से इसकी जगह अब स्ट्रक्चर्स पर readonly मॉडिफायर का उपयोग करके तय किया गया है।





readonly-attribute