C# 3.0 نوع عام الاستدلال - تمرير تفويض بوصفها وظيفة معلمة

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

سؤال

وأنا أتساءل لماذا C# 3.0 مترجم غير قادر على استنتاج نوع الأسلوب عندما يتم تمريره كمعلمة إلى وظيفة عامة عندما يمكن أن ضمنا إنشاء مندوب نفس الأسلوب.

هنا مثال:

class Test
{
    static void foo(int x) { }
    static void bar<T>(Action<T> f) { }

    static void test()
    {
        Action<int> f = foo; // I can do this
        bar(f); // and then do this
        bar(foo); // but this does not work
    }   
}

كنت أعتقد أنني سوف تكون قادرة على تمرير foo إلى bar و يكون مترجم نستنتج نوع Action<T> من التوقيع على وظيفة يتم تمريرها ولكن هذا لا يعمل.ومع ذلك لا يمكن إنشاء Action<int> من foo دون صب لذلك ليس هناك سبب شرعي أن المترجم لا يمكن أيضا أن تفعل الشيء نفسه عن طريق نوع الاستدلال?

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

المحلول

ربما هذا سيجعل الأمر أكثر وضوحا:

public class SomeClass
{
    static void foo(int x) { }
    static void foo(string s) { }
    static void bar<T>(Action<T> f){}
    static void barz(Action<int> f) { }
    static void test()
    {
        Action<int> f = foo;
        bar(f);
        barz(foo);
        bar(foo);
        //these help the compiler to know which types to use
        bar<int>(foo);
        bar( (int i) => foo(i));
    }
}

فو ليس العمل - فو هو أسلوب الفريق.

  • في إحالة البيان المترجم يمكن أن أقول بوضوح فو الذي تتحدث عنه منذ الباحث النوع المحدد.
  • في تم استنفاد(فو) بيان المترجم يمكن أن أقول فو الذي تتحدث عنه منذ الباحث النوع المحدد.
  • في شريط(فو) بيان, أنها يمكن أن تكون أي فو مع معلمة واحدة - حتى المترجم يستسلم.

تحرير:لقد تم إضافة اثنين (أكثر) من الطرق لمساعدة المترجم معرفة نوع (أي - كيفية تخطي الاستدلال الخطوات).

من قراءتي المقالة في JSkeet الجواب, قرار لا نستنتج نوع يبدو أن يكون على أساس متبادل infering السيناريو ، مثل

  static void foo<T>(T x) { }
  static void bar<T>(Action<T> f) { }
  static void test()
  {
    bar(foo); //wut's T?
  }

منذ العام المشكلة unsolve قادرة ، اختاروا ترك مشاكل محددة حيث حل يوجد حل.

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

نصائح أخرى

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

.

لهذا السبب، حتى عندما لا يكون هناك واحد فقط فو طريقة، في اشارة الى فو (المعروفة باسم مجموعة الأسلوب) لا يمكن أن يلقي لمندوب غير نوع معين، مثل Action<T> ولكن فقط لمندوب نوع معين مثل Action<int>.

وهذا أمر غريب قليلا، نعم. المواصفات C # 3.0 لنوع الاستدلال من الصعب قراءة ولها اخطاء في ذلك، ولكن يبدو مثل ذلك يجب أن تعمل. في المرحلة الأولى (القسم 7.4.2.1) وأعتقد أن هناك من الخطأ - فإنه لا ينبغي أن نذكر مجموعة الأسلوب في النقطة الأولى (كما انهم لا تغطيها صريح نوع المعلمة الاستدلال (7.4.2.7) - وهو ما يعني أنها يجب أن تستخدم . نوع الانتاج الاستدلال (7.4.2.6) أن <م> يبدو مثل ذلك يجب أن تعمل - ولكن من الواضح أنه لا: (

وأنا أعلم أن MS تتطلع لتحسين المواصفات لنوع الاستدلال، لذلك قد تصبح أكثر وضوحا قليلا. وأعلم أيضا أنه بغض النظر عن صعوبة قراءته، وهناك قيود على الجماعات طريقة ونوع الاستدلال - القيود التي يمكن أن تكون خاصة فتش عندما المجموعة الطريقة هي في الواقع سوى طريقة واحدة، باعتراف الجميع

واريك ليبرت لديه دخول بلوق على <لأ href = "http://blogs.msdn.com/ericlippert/archive/2007/11/05/c-3-0-return-type-inference-does-not -work على اساس الأعضاء groups.aspx "يختلط =" نوفولو noreferrer "> عودة نوع الاستدلال لا يعمل مع مجموعات طريقة حيث هو مماثلة إلى هذه الحالة - ولكن هنا نحن لسنا المهتمة في نوع الإرجاع، فقط على نوع المعلمة. فمن الممكن أن وظائف أخرى في حياته سلسلة نوع الاستدلال قد تساعد على الرغم من.

ونضع في اعتبارنا أن الإحالة

Action<int> f = foo;

وبالفعل الكثير من السكر النحوي. البرمجي في الواقع رمز لهذا البيان:

Action<int> f = new Action<int>(foo);

واستدعاء الأسلوب المطابق يجمع دون مشكلة:

bar(new Action<int>(foo));

وFWIW، لذلك لا يساعد مترجم للاستدلال على وسيطة نوع:

bar<int>(foo);

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

وفقط للتأكد من اكتمالها، وهذا ليس خاصا C #: فشل نفس رمز VB.NET بالمثل:

Imports System

Module Test
  Sub foo(ByVal x As integer)
  End Sub
  Sub bar(Of T)(ByVal f As Action(Of T))
  End Sub

  Sub Main()
    Dim f As Action(Of integer) = AddressOf foo ' I can do this
    bar(f) ' and then do this
    bar(AddressOf foo) ' but this does not work
  End Sub
End Module

وخطأ BC32050: نوع المعلمة 'T' ل 'الفرعية شريط العامة (وT) و (وSystem.Action (من T)) لا يمكن الاستدلال على ذلك

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