في C#، لماذا تعتبر السلسلة نوع مرجعي يتصرف مثل نوع القيمة؟

StackOverflow https://stackoverflow.com/questions/636932

سؤال

السلسلة هي نوع مرجعي على الرغم من أنها تحتوي على معظم خصائص نوع القيمة مثل كونها غير قابلة للتغيير ولديها == محملة بشكل زائد لمقارنة النص بدلاً من التأكد من أنها تشير إلى نفس الكائن.

لماذا لا تعتبر السلسلة مجرد نوع قيمة إذن؟

هل كانت مفيدة؟

المحلول

وسلاسل ليست أنواع قيمة لأنها يمكن أن تكون ضخمة، وتحتاج إلى تخزينها على الكومة. أنواع القيم (في جميع الأجهزة من CLR اعتبارا من بعد) المخزنة على المكدس. كومة تخصيص سلاسل من شأنه كسر كل أنواع الأشياء: المكدس 1MB الوحيد ل32 بت و 4MB 64 بت، وكنت قد لمربع كل سلسلة، تكبد ركلة جزاء نسخة، هل يمكن أن السلاسل لا المتدرب، واستخدام الذاكرة سوف بالون، الخ ...

(تحرير:.. واضاف التوضيح حول نوع القيمة تخزين كونه التفاصيل التنفيذ، الأمر الذي يؤدي إلى هذه الحالة التي لدينا نوع مع sematics قيمة لا يرث من System.ValueType بفضل بن)

نصائح أخرى

وليس من نوع قيمة بسبب الأداء (المكان والزمان!) سيكون رهيبا لو كانت نوع القيمة وكان قيمة لها ليتم نسخها في كل مرة ونقلوها الى وعاد من الأساليب، وما إلى ذلك.

وله دلالات قيمة للحفاظ على العالم عاقل. يمكنك أن تتخيل مدى صعوبة أن يكون لرمز إذا

string s = "hello";
string t = "hello";
bool b = (s == t);

ومجموعة b أن false؟ تخيل كيف الترميز الصعب تقريبا أن أي تطبيق أن يكون.

يعد التمييز بين أنواع المراجع وأنواع القيم بمثابة مقايضة أداء في تصميم اللغة.تحتوي أنواع المراجع على بعض النفقات العامة على الإنشاء والتدمير وجمع البيانات المهملة، لأنه يتم إنشاؤها في الكومة.من ناحية أخرى، فإن أنواع القيم لها حمل إضافي على استدعاءات الأسلوب (إذا كان حجم البيانات أكبر من المؤشر)، لأنه يتم نسخ الكائن بالكامل بدلاً من مجرد مؤشر.نظرًا لأن السلاسل يمكن أن تكون (وعادة ما تكون كذلك) أكبر بكثير من حجم المؤشر، فقد تم تصميمها كأنواع مرجعية.أيضًا، كما أشار Servy، يجب معرفة حجم نوع القيمة في وقت الترجمة، وهذا ليس هو الحال دائمًا بالنسبة للسلاسل.

مسألة القابلية للتغيير هي قضية منفصلة.يمكن أن تكون كل من أنواع المراجع وأنواع القيم قابلة للتغيير أو غير قابلة للتغيير.عادةً ما تكون أنواع القيم غير قابلة للتغيير، نظرًا لأن دلالات أنواع القيم القابلة للتغيير يمكن أن تكون مربكة.

عادةً ما تكون أنواع المراجع قابلة للتغيير، ولكن يمكن تصميمها على أنها غير قابلة للتغيير إذا كان ذلك منطقيًا.يتم تعريف السلاسل على أنها غير قابلة للتغيير لأنها تجعل بعض التحسينات ممكنة.على سبيل المثال، إذا تكررت نفس السلسلة الحرفية عدة مرات في نفس البرنامج (وهو أمر شائع جدًا)، فيمكن للمترجم إعادة استخدام نفس الكائن.

فلماذا يتم تحميل "==" بشكل زائد لمقارنة السلاسل بالنص؟لأنه من أكثر الدلالات فائدة.إذا كانت سلسلتان متساويتان في النص، فقد يكونان أو لا يكونان نفس مرجع الكائن بسبب التحسينات.لذا فإن مقارنة المراجع غير مجدية إلى حد كبير، في حين أن مقارنة النص هي دائمًا ما تريده.

بشكل عام، السلاسل لديها ما يسمى دلالات القيمة.هذا مفهوم أكثر عمومية من أنواع القيمة، وهو عبارة عن تفاصيل تنفيذ محددة لـ C#.تحتوي أنواع القيم على دلالات قيمة، ولكن قد تحتوي أنواع المراجع أيضًا على دلالات قيمة.عندما يكون للنوع دلالات قيمة، لا يمكنك حقًا معرفة ما إذا كان التنفيذ الأساسي هو نوع مرجعي أو نوع قيمة، لذلك يمكنك اعتبار ذلك تفاصيل التنفيذ.

وهذا هو الجواب في وقت متأخر إلى السؤال القديم، ولكن كل الإجابات الأخرى مفقودة هذه النقطة، وهي أن صافي لم يكن لديك الوراثة حتى NET 2.0 في عام 2005.

وString هو نوع مرجع بدلا من نوع قيمة لأن على كان من الأهمية بمكان لمايكروسوفت لضمان أن سلاسل يمكن تخزينها في الطريقة الأكثر فعالية في مجموعات غير عامة ، أو مثل System.Collection.ArrayList.

وتخزين من نوع قيمة في مجموعة غير عام يتطلب تحويل خاص لنوع من object وهو ما يسمى الملاكمة. عندما مربعات CLR نوع قيمة، فإنه يلتف قيمة داخل System.Object ويخزنها على كومة المدارة.

وقراءة قيمة من مجموعة يتطلب عملية عكسية وهو ما يسمى علبته.

وكلا الملاكمة وعلبته لها تكلفة لا يستهان بها: الملاكمة تتطلب مخصصات إضافية، علبته يتطلب اكتب فحص

وبعض الإجابات تدعي بشكل غير صحيح لا يمكن أبدا أن تم تنفيذ ذلك string كنوع قيمة لأن حجمه متغير. في الواقع أنه من السهل لتنفيذ سلسلة كهيكل البيانات ذات طول ثابت باستخدام استراتيجية تحسين سلسلة الصغيرة: سيتم تخزينها السلاسل في الذاكرة مباشرة على شكل سلسلة من أحرف Unicode باستثناء السلاسل الكبيرة التي سيتم تخزينها كمؤشر إلى وجود مخزن مؤقت الخارجي. ويمكن تصميم كل من تمثيلات لديهم نفس طول ثابت، أي حجم المؤشر.

إذا الوراثة كانت موجودة من يوم واحد أعتقد أن وجود سلسلة كنوع قيمة ربما يكون أفضل حل، مع دلالات أبسط، واستخدام ذاكرة أفضل وأفضل موقع ذاكرة التخزين المؤقت. A List<string> تحتوي على سلاسل صغيرة فقط يمكن أن يكون كتلة متجاورة واحد من الذاكرة.

ليست السلاسل فقط هي أنواع مرجعية غير قابلة للتغيير.مندوبون متعددو الممثلين أيضًا.هذا هو السبب في أنها آمنة للكتابة

protected void OnMyEventHandler()
{
     delegate handler = this.MyEventHandler;
     if (null != handler)
     {
        handler(this, new EventArgs());
     }
}

أفترض أن السلاسل غير قابلة للتغيير لأن هذه هي الطريقة الأكثر أمانًا للتعامل معها وتخصيص الذاكرة.لماذا هم ليسوا أنواع القيمة؟المؤلفون السابقون على حق بشأن حجم المكدس وما إلى ذلك.أود أيضًا أن أضيف أن جعل السلاسل أنواعًا مرجعية يسمح بحفظ حجم التجميع عند استخدام نفس السلسلة الثابتة في البرنامج.إذا قمت بتحديد

string s1 = "my string";
//some code here
string s2 = "my string";

من المحتمل أن يتم تخصيص كلا مثيلي ثابت "سلسلتي" في التجميع الخاص بك مرة واحدة فقط.

إذا كنت ترغب في إدارة السلاسل مثل النوع المرجعي المعتاد، فضع السلسلة داخل StringBuilder(string s) الجديد.أو استخدم MemoryStreams.

إذا كنت تريد إنشاء مكتبة، حيث تتوقع تمرير سلاسل ضخمة في وظائفك، فقم إما بتعريف المعلمة على أنها StringBuilder أو على أنها Stream.

وبالإضافة إلى ذلك، يتم تطبيق طريقة السلاسل (مختلفة لكل منصة) وعند بدء خياطة معا. مثل استخدام StringBuilder. ومن allocats عازلة لللك نسخ إلى، بمجرد وصولك إلى النهاية، فإنه يخصص المزيد من الذاكرة بالنسبة لك، على أمل أنه إذا كنت تفعل أداء سلسلة كبيرة لن يعوق.

وربما جون السكيت يمكن أن تساعد حتى هنا؟

وهو أساسا مشكلة أداء.

وجود سلاسل تتصرف مثل نوع القيمة يساعد عند كتابة التعليمات البرمجية، ولكن بعد أن يكون نوع قيمة من شأنه أن يجعل ضرب أداء ضخمة.

لنظرة متعمقة، وإلقاء نظرة خاطفة على على سلاسل في .NET Framework.

وكيف يمكن أن أقول لكم string هو نوع مرجع؟ لست متأكدا من أنه يهم كيف يتم تنفيذه. السلاسل في C # هي ثابتة بدقة بحيث لم يكن لديك ما يدعو للقلق حول هذه المسألة.

في الواقع، تحتوي السلاسل على عدد قليل جدًا من أوجه التشابه مع أنواع القيمة.بالنسبة للمبتدئين، ليست كل أنواع القيم غير قابلة للتغيير، يمكنك تغيير قيمة Int32 كما تريد وستظل نفس العنوان على المكدس.

السلاسل غير قابلة للتغيير لسبب وجيه جدًا، ليس لها علاقة بكونها نوعًا مرجعيًا، ولكن لها علاقة كبيرة بإدارة الذاكرة.يعد إنشاء كائن جديد عندما يتغير حجم السلسلة أكثر كفاءة من تغيير الأشياء في الكومة المُدارة.أعتقد أنك تمزج بين أنواع القيمة/المرجع ومفاهيم الكائنات غير القابلة للتغيير.

بقدر "==":كما قلت، "== هو عامل تحميل زائد، ومرة ​​أخرى تم تنفيذه لسبب وجيه للغاية لجعل إطار العمل أكثر فائدة عند العمل مع السلاسل.

في كلمات بسيطة جدا يمكن علاج أي قيمة لديه حجم محدد كنوع قيمة.

وليس مجرد بسيطة مثل مصنوعة سلاسل تتكون من الأحرف المصفوفات. أنظر إلى سلاسل كما صفائف حرف []. لذلك هم على كومة لأنه يتم تخزين موقع الذاكرة المرجعية على المكدس ويشير إلى بداية موقع ذاكرة صفيف على الكومة. ومن غير المعروف حجم سلسلة قبل أن يتم تخصيص ذلك ... مثالية لالكومة.

وهذا هو السبب في السلسلة ثابتة حقا لأنه عندما تقوم بتغييره حتى لو كان من نفس الحجم المترجم لا يعرف أن لديه وتخصيص مجموعة جديدة وتعيين الأحرف إلى المواقع في مجموعة. فمن المنطقي إذا كنت تفكر في سلاسل كوسيلة أن اللغات حمايتك من الحاجة إلى تخصيص الذاكرة على الطاير (اقرأ C مثل البرمجة)

في خطر الحصول على تصويت سلبي غامض آخر...حقيقة أن الكثيرين يذكرون المكدس والذاكرة فيما يتعلق بأنواع القيمة والأنواع البدائية هو أنها يجب أن تتناسب مع سجل في المعالج الدقيق.لا يمكنك دفع شيء ما أو دفعه إلى/من المكدس إذا كان يستغرق عددًا أكبر من البتات مما يحتوي عليه السجل.... التعليمات هي، على سبيل المثال، "pop eax" - لأن عرض eax يبلغ 32 بت على نظام 32 بت.

يتم التعامل مع الأنواع البدائية ذات الفاصلة العائمة بواسطة FPU، الذي يبلغ عرضه 80 بت.

تم تحديد كل هذا قبل فترة طويلة من ظهور لغة OOP لإخفاء تعريف النوع البدائي وأفترض أن نوع القيمة هو مصطلح تم إنشاؤه خصيصًا للغات OOP.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top