سؤال

سؤالي هو:

إذا كنت سأبني أ DynamicMethod الكائن ، المقابل ل ConstructorInfo.invoke اتصل ، ما هي أنواع IL التي أحتاج إلى تنفيذها من أجل التعامل مع جميع أنواع الوسيطات (أو معظمها) ، عندما يمكنني ضمان أن النوع المناسب وعدد الوسائط سيتم تمريره قبل إجراء المكالمة؟


خلفية

أنا في تكراري الثالث لحاوية IOC الخاصة بي ، وأقوم حاليًا ببعض التنميط لمعرفة ما إذا كانت هناك أي مناطق يمكنني من خلالها حلق كميات كبيرة من الوقت.

شيء واحد لاحظته هو أنه عند الحل إلى نوع ملموس ConstructorInfo.invoke, ، تمرير مجموعة من الحجج التي عملت بها.

ما لاحظته هو أن طريقة الاستدعاء لديها قدر كبير من النفقات العامة ، وأنا أتساءل عما إذا كان معظم هذا هو مجرد تطبيقات مختلفة لنفس الشيكات التي أقوم بها.

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

عند القيام بجلسة ملامح تحتوي على مليون مكالمة إلى طريقة حلها ، ثم استبدالها بـ DynamicMethod التنفيذ الذي يحاكي دعوة الاستدعاء ، كانت توقيت التوصيف هكذا:

  • ConstructorInfo.invoke: 1973ms
  • DynamicMethod: 93ms

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

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

لذلك ، ستأخذ الطريقة الديناميكية في صفيف كائن ، وإرجاع الكائن المبني ، وأعرف بالفعل كائن البناء المعني.

لذلك ، يبدو أن الطريقة الديناميكية ستتكون من IL التالية:

l001:    ldarg.0      ; the object array containing the arguments
l002:    ldc.i4.0     ; the index of the first argument
l003:    ldelem.ref   ; get the value of the first argument
l004:    castclass T  ; cast to the right type of argument (only if not "Object")
(repeat l001-l004 for all parameters, l004 only for non-Object types,
 varying l002 constant from 0 and up for each index)
l005:    newobj ci    ; call the constructor
l006:    ret

هل هناك أي شيء آخر أحتاج إلى مراعاته؟

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

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

المحلول

بالنسبة لأنواع القيمة ، يجب أن تكون الخطوة L004 l004: unbox.any T.

أسهل طريقة لمعرفة IL الصحيح الذي تحتاج إلى إنشاءه هي النظر إلى ما تم إنشاؤه بواسطة برنامج التحويل البرمجي C# باستخدام بعض رمز الاختبار.

static void Test(object[] args)
{
  TestTarget((string)args[0], (int)args[1], (DateTime?)args[2]);
}

static void TestTarget(string s, int i, DateTime? dt){}

يجمع إلى:

L_0000: ldarg.0 
L_0001: ldc.i4.0 
L_0002: ldelem.ref 
L_0003: castclass string
L_0008: ldarg.0 
L_0009: ldc.i4.1 
L_000a: ldelem.ref 
L_000b: unbox.any int32
L_0010: ldarg.0 
L_0011: ldc.i4.2 
L_0012: ldelem.ref 
L_0013: unbox.any [mscorlib]System.Nullable`1<valuetype [mscorlib]System.DateTime>
L_0018: call void Program::TestTarget(string, int32, valuetype [mscorlib]System.Nullable`1<valuetype [mscorlib]System.DateTime>)
L_001d: ret 

نصائح أخرى

هناك مكتبات متاحة لتسهيل (وأسرع) للعمل مع التفكير. على سبيل المثال، أسرع يمكن إنشاء IL لاستدعاء أي مُنشئ - كل ما عليك فعله هو تمرير الوسيطات التي تريد استخدامها في المنشئ.

// note: class must have constructor with (int,string,string) signature
object obj = someType.CreateInstance( new { id=1, name="jens", foo="bar" } );

المكتبة قادرة أيضًا على البحث عن مُنشئ مناسب للاتصال ، في حالة عدم وجود مجموعة من المعلمات التي تتطابق تمامًا مع مُنشئ.

// try to map id, name and foo to constructor parameters
// allows changing the order and permit fallback to setting fields/properties
// e.g. might result in call to ctor(string,string) and set field "id"
object obj = someType.TryCreateInstance( new { id=1, name="jens", foo="bar" } );

إخلاء المسئولية: أنا متورط في المشروع المذكور كمساهم.

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