سؤال

دعونا نحصين رمز MSIL الذي تم إنشاؤه للطريقة العامة التالية:

public static U BoxValue<T, U>(T value)
  where T : struct, U
  where U : class
{
  return value;
}

نظرة:

.method public hidebysig static !!U  BoxValue<valuetype .ctor
 ([mscorlib]System.ValueType, !!U) T,class U>(!!T 'value') cil managed
{
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  box        !!T
  IL_0006:  unbox.any  !!U
  IL_000b:  ret
}

ولكن بالنسبة للرمز العام أعلاه، يجب أن يكون تمثيل IL أكثر كفاءة:

  IL_0000:  ldarg.0
  IL_0001:  box        !!T
  IL_0006:  ret

ومن المعروف من القيود أن القيمة محاصر في نوع مرجع. Unbox.any OpCode غير زائد تماما لأنه بعد box Opcode القيمة في مكدس Il ستكون بالفعل مرجع صالح !!U, ، يمكن استخدامها دون أي unboxing.

لماذا لا يستخدم برنامج التحويل البرمجي C #. 3.0 تقييد البيانات الوصفية لتنبعث رمز عام أكثر كفاءة؟ unbox.any يعطي النفقات العامة الصغيرة (فقط 4x-5x أبطأ)، ولكن لماذا لا تنبعث منه رائحة أفضل في هذا السيناريو؟

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

المحلول

يبدو أن المترجم يقوم بذلك بسبب بعض المشكلات مع المدقق.

لا يمكن التحقق منه IL الذي ترغب في إنشاء مترجم يمكن التحقق منه، وبالتالي لا يمكن لمجموع التحويل البرمجي C # إنشاءه (يجب التحقق من جميع Code C # خارج سياقات "غير آمنة").

يتم تقديم قواعد "توافق نوع التحقق" في القسم 1.8.1.2.3، Partion III من مواصفات ECMA.

يقولون أن نوع "S" متوافق مع نوع "T" أو (S: = T) باستخدام القواعد التالية:

  1. : = الانعكاسية] لجميع أنواع التحقق S: = S
  2. : = متعدية] لجميع أنواع التحقق S، T، وأجلك إذا كانت S: = T و T: = U، ثم S: = U.
  3. S: = T إذا كانت S الفئة الأساسية من T أو واجهة تنفذها T و T ليست نوعا من القيمة.
  4. الكائن: = T إذا كانت T نوع الواجهة.
  5. S: = T إذا كانت S و T كلا الواجهات وتنفيذ ر يتطلب تنفيذ S
  6. S: = NULL إذا كان S نوع كائن أو واجهة
  7. S []: = T [] إذا كانت S: = T والصفوفات إما كلاهما كلاهما (مقرها صفر، رتب واحد) أو لا يوجد ناقل وهما لهما نفس الرتبة. (تتناول هذه القاعدة مع صفيف التباين.)
  8. إذا كانت S و T هي مؤشرات الطريقة، ثم S: = T إذا كانت التوقيعات (أنواع الإرجاع وأنواع المعلمات واتفاقية الاتصال) هي نفسها.

هذه القواعد، الوحيدة التي قد تكون قابلة للتطبيق في هذه الحالة هي رقم 3.

ومع ذلك، لا ينطبق # 3 على التعليمات البرمجية الخاصة بك، لأن "U" ليست فئة أساسية من 'T'، وهي ليست واجهة أساسية من 'T'، بحيث يعود الشيك "أو" خطأ FALSE.

هذا يعني أن بعض التعليمات يجب تنفيذها من أجل تحويل محاصر T إلى U بطريقة ستجتاز المدقق.

أوافق عليك أن قواعد التحقق يجب تغييرها، بحيث توليد الكود الذي تريده هو التحقق منه في الواقع.

من الناحية الفنية، ومع ذلك، فإن المترجم يقوم بالشيء "الصحيح" بناء على مواصفات ECMA.

يجب عليك تقديم خطأ مع شخص ما في Microsoft.

نصائح أخرى

هذه القيود تبدو غريبة:

where T : struct, U
where U : class

T هو نوع القيمة ولكن في نفس الوقت يجب أن يرث من يو وهو نوع مرجعي. أتساءل أنواع يمكن أن تلبي القيود المذكورة أعلاه والسماح لنا بالاتصال بهذه الطريقة.

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