الملاكمة, ما المفضل لديك و التي تظن هي أسرع ؟

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

  •  22-08-2019
  •  | 
  •  

سؤال

باختصار أعتقد الملاكمة هو مصدر إزعاج.دعونا نلقي نظرة على بعض البدائل...

public class Box<T> 
    where T : struct
{
    public T Value { get; set; }

    public static implicit operator T(Box<T> box)
    {
        return box.Value;
    }
}

النظام.Int32 مستمد من فئة مجردة النظام.ValueType التي تستمد من النظام الطبقي.الكائن.لا يمكنك أن تستمد من النظام.ValueType في C# ولكن أعتقد أن البنية الكلمة يفعل ذلك بالضبط و CLI تسلم هذا النوع من نوع التعاريف بأنها تمر القيمة الدلالية.على أية حال, عندما البنية تعيين نوع الكائن الملاكمة يحدث.أنا لا أريد أن ننشغل في الملاكمة في حد ذاتها بدلا من ذلك أريد أن ندخل في صلب الموضوع.

بحثت في بعض IL التي تم إنشاؤها بواسطة برنامج التحويل البرمجي C#.

object obj = 1;

.locals init ([0] object obj)
L_0000: nop 
L_0001: ldc.i4.1 
L_0002: box int32 // Convert a value type (of the type specified in valTypeToken) to a true object reference. 
L_0007: stloc.0 

وجدت هذا على MSDN...

نوع قيمة اثنين منفصلة التمثيل داخل لغة مشتركة البنية التحتية (CLI):

  • A 'الخام' النموذج المستخدم عند قيمة نوع هو جزءا لا يتجزأ من داخل كائن آخر أو على المكدس.

  • A 'محاصر' النموذج ، حيث البيانات في نوع القيمة ملفوفة (محاصر) إلى كائن لذلك يمكن أن توجد ككيان مستقل.

هذا يقودني إلى استنتاج أنه ينبغي أن يكون على قدم المساواة مكلفة إلى كتابة التعليمات البرمجية مثل هذا...

var box = obj as Box<int>;
if (box != null)
{
    Console.WriteLine(box.Value);
}

إذا كنت تنوي تمرير نفس القيمة حول باعتبارها النظام.كائن لا أريد حقا أن خدمة unbox و مربع ValueType كل مرة ؟ احساسي يقول لي لا, ولكن أنا غير قادر على العثور حقا جيدة الدافع أي تعليق على كل هذا يردد ؟

تحرير

أي شخص من أي وقت مضى تجد نفسها تفعل هذا ؟ أنا أدرك أنه قد تبدو غريبة ولكن عند نقطة واحدة وجدت نفسي في موقف كنت أردت مجردة الحسابات على أساس من عدة تمثيلات مختلفة.أنا فعلت هذا مع تعبيرات لامدا.ليس حقا المتعلقة الملاكمة لكنه سمح لي أن علاج أي ValueType (هذه البنية هو مريح 8 بايت محاذاة) كما لو كانت واحدة من نوع "ReinterpretCast".

[StructLayout(LayoutKind.Explicit)]
public struct ReinterpretCast
{
    [FieldOffset(0)] sbyte @sbyte;
    [FieldOffset(0)] byte @byte;
    [FieldOffset(0)] short @ushort;
    [FieldOffset(0)] ushort @short;
    [FieldOffset(0)] int @int;
    [FieldOffset(0)] uint @uint;
    [FieldOffset(0)] long @long;
    [FieldOffset(0)] ulong @ulong;
    [FieldOffset(0)] float @float;
    [FieldOffset(0)] double @double;
}
هل كانت مفيدة؟

المحلول

أنا لست متأكدا تماما من سؤالك هنا.هل يسأل عما إذا كان الحل هو ربما أفضل من العادي الملاكمة ؟ لديها بالتأكيد بعض الاستئناف.إذا كنت تسأل لماذا الملاكمة لم يكن تنفيذ هذه الطريقة في المقام الأول, فقط تذكر أن .صافي لم الأدوية أن تبدأ مع.

تحرير:الملاكمة هي نادرة نسبيا مع الأدوية على أي حال.لا ننسى أن سوف لا يزال لديك للقيام runtime يلقي إذا إشارة إلى مثيل من نوع مرت بالجوار object (كما هو الحال عادة على أي حال للملاكمة).لا تنسى أيضا واجهات - إذا كانت قيمة نوع تنفذ واجهة, حتى لا يقابلها نوع مرجع المستخدمة في الملاكمة.الحل لن يزيل ذلك استخدام الملاكمة, كما لا يمكنك أن تجعل الخاصة بك نوع "التظاهر" لتنفيذ واجهة.(كنت قد تكون قادرة على أن تفعل شيئا مع DLR ، ولكن بحلول ذلك الوقت أكثر من نقطة وقد خسر :)

نصائح أخرى

ما نفكر به هو أسرع هو غير ذي صلة تماما.فقط التعريف هو ذات الصلة عند النظر في ما هو أسرع.

"إذا كنت تنوي تمرير نفس القيمة حول ككائن لا أريد حقا خدمة unbox/صندوق في كل مرة؟"

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

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

لكن كما قال الجميع, أنت لا تحتاج إلى "تمرير نفس القيمة حول كائن" على أي حال.هذا ما الأدوية ، إلا إذا كنت تعمل على الإطار 1.x.الملاكمة كان أكثر أهمية عندما BCL جمع الصفوف استخدام النظام.موضوع أي نوع القيمة التي ذهبت في كان محاصر.

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

عنوان السؤال يفتقد ما أعتقد هو الجانب الأكثر إثارة للاهتمام:ما هي الطريقة هو النظام الملاكمة السلوك يختلف من Box<T> نوع.هناك عدد قليل من الاختلافات:

(1) محاصر T سيتم تنفيذ نفس واجهات كما T, باستخدام نفس الكود ولكن في الغالب سوف تتصرف باستخدام فئة دلالات بدلا من القيمة دلالات ، ولكن مع ملتوي Equals الأسلوب.

(2) تحور محاصر T عموما سوف يكون ازعاج في C# أو vb.net لكن محاصر T لن يكون حقا ثابتا منذ غير موثوق بها ويمكن التحقق منها قانون يسمح له بذلك ، حتى لو كان محرجا في بعض اللغات (فإنه من السهل في C++/CLI).حتى أنواع مثل محاصر Int32 هي قابلة للتغيير عندما محاصر.وعلى النقيض من ذلك ، يمكن تحديد ImmutableBox<T>, التي أخذت منشئ من نوع T, الذي الحقول سوف يكون حقا غير قابل للتغيير.

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

(4) ضمني من الزهر T إلى Box<T> لن يحول دون إمكانية نوع T تعريف ضمني يلقي إلى واجهة نوع.على النقيض من ذلك, لأن كل أنواع ضمنا إلى castable Object, لا vb.net ولا C# سوف تسمح بإمكانية ضمني المستخدم يلقي بين البنية نوع واجهة.

(5) دون المتخصصة مترجم دعم الملاكمة ، لن يكون هناك أي وسيلة بالنسبة أساليب حاليا قبول المعلمة-مجموعة من Object[] تلقائيا تحويل المعلمات من أنواع مثل Int32 إلى Box<Int32>.من ناحية أخرى ، إضافة وسيلة من الطالبة أن بعض المعلمات تكون السيارات-محاصر قد تكون أفضل من وجود ضمني الملاكمة في كل مكان.لاحظ أنه إذا كانت مثل هذه الوسائل موجودة ، يمكن أن expecify أن كل معلمة يجب أن توضع في Box<T>, ، مما يجعل من الممكن التمييز بين تمرير T و Box<T> (لأن هذا الأخير أن تمرير مثل Box<Box<T>>.

حسنا, هناك عدة مواضيع كنت لمس هنا.أولا, دعونا نلقي نظرة على أنواع قيمة و لماذا كانت موجودة.أنواع قيمة ما كنت تستخدم عند الحاجة قيمة دلالات:

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

جميع أنواع رقمية ، على سبيل المثال ، هي أنواع قيمة على وجه التحديد لأنها تحتاج إلى أن يكون قيمة دلالات.إذا كان المتغير x له قيمة 17 و تعيين x إلى y, ثم y سوف يكون لها الخاصة قيمة 17 و تزايد y لن تتغير x 18.لذلك ، ما لم يكن لديك سبب وجيه ، واستخدام البنية فقط عند تحديد النوع الذي يحتاج إلى القيمة دلالات.

على مستوى التنفيذ ، قيمة دلالات تنفذ باستخدام في خط التوزيع.يمكنك قراءة المزيد حول هذا الموضوع هنا.

وهذا يقودنا إلى الملاكمة.متى الملاكمة يحدث ؟ عندما يلقي القيمة نوع إلى نوع مرجع.كنت تستخدم نوع وجوه وكمثال على ذلك, ولكن مع C# الوراثة ، هذا ما يجب أن يحدث نادرا في الممارسة العملية.أكثر تواترا الحالة سيكون يلقي نوع القيمة إلى واجهة ؛ على سبيل المثال, صب مزدوج في IEquatable أو IComparable.على أي حال, إذا كنت يلقي valu نوع إلى نوع مرجع الملاكمة و يجب أن تحدث.

ماذا يحدث حقا عندما الملاكمة يحدث?A نسخ على سبيل المثال أن تكون محاصر ويوضع على كومة من ككائن مستقل ، بحيث يمكن أن يكون بأمان المشار إليها حتى عندما المثال الأصلي يخرج من نطاق.إذا لم يكن الملاكمة ، سيكون من السهل الحصول على CLR إلى محاولة الوصول إلى ذاكرة غير صالحة ونحن نعلم جميعا أن baaaaad شيء.

لذا هو الملاكمة جيدة أو سيئة ؟ من جهة أنه جيد لأنه يسمح لك بأمان يلقي قيمة الأنواع إلى أنواع مرجع عند الحاجة إليها.من ناحية أخرى, أنه يخلق "القمامة" -- قصيرة الأجل الحالات من الكائنات التي تحصل على التخلص منها ، إضافة إلى العمل على جمع القمامة القيام به.هل هذا سيء ؟ فقط في بعض الحالات, مثل النامي XNA الألعاب.إذا كانت هذه هي الحالة, سوف تحتاج إلى تجنب غير المنضبط الملاكمة;إذا كان الأمر كذلك, أنا أيضا أدعوك إلى التوقف عن بلدي بلوق حيث لدي بعض بت المشورة بشأن هذا الموضوع.

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