لماذا لا يدعم C# الأنواع العامة الضمنية في مُنشئي الفصل؟

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

  •  09-06-2019
  •  | 
  •  

سؤال

لا تتطلب منك لغة C# تحديد معلمة نوع عامة إذا كان المترجم يستطيع استنتاجها، على سبيل المثال:

List<int> myInts = new List<int> {0,1,1,
    2,3,5,8,13,21,34,55,89,144,233,377,
    610,987,1597,2584,4181,6765};

//this statement is clunky
List<string> myStrings = myInts.
    Select<int,string>( i => i.ToString() ).
    ToList<string>();

//the type is inferred from the lambda expression
//the compiler knows that it's taking an int and 
//returning a string
List<string> myStrings = myInts.
    Select( i => i.ToString() ).
    ToList();

يعد هذا ضروريًا للأنواع المجهولة حيث لا تعرف ما هي معلمة النوع (في التحسس الذكي تظهر كـ 'a) لأنه تمت إضافته بواسطة المترجم.

لا تسمح لك معلمات النوع على مستوى الفصل بالقيام بذلك:

//sample generic class
public class GenericDemo<T> 
{
    public GenericDemo ( T value ) 
    {
        GenericTypedProperty = value;
    }

    public T GenericTypedProperty {get; set;}
}

//why can't I do:
int anIntValue = 4181;
var item = new GenericDemo( anIntValue ); //type inference fails

//however I can create a wrapper like this:
public static GenericDemo<T> Create<T> ( T value )
{
    return new GenericDemo<T> ( value );
}

//then this works - type inference on the method compiles
var item = Create( anIntValue );

لماذا لا يدعم C# استنتاج النوع العام على مستوى الفصل الدراسي؟

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

المحلول

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

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

class Foo<T> {
    public Foo(T x) { … }
}

// Notice: non-generic class overload. Possible in C#!
class Foo {
    public static Foo<T> ctor<T>(T x) { return new Foo<T>(x); }
}

var x = Foo.ctor(42);

نظرًا لأن هذا الرمز يعمل بالفعل، فقد أظهرنا أن المشكلة ليست مشكلة دلالات ولكنها ببساطة مشكلة نقص الدعم.أعتقد أنني يجب أن أستعيد مشاركتي السابقة.؛-)

نصائح أخرى

لماذا لا يدعم C# استنتاج النوع العام على مستوى الفصل الدراسي؟

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

لتوضيح حالة متطرفة يكون فيها الحل مستحيلًا، تخيل الفئة التالية وأخبرني بما يجب على المترجم فعله:

class Foo<T> {
    public Foo<U>(U x) { }
}

var x = new Foo(1);

شكرًا كونراد، هذه استجابة جيدة (+1)، ولكن فقط للتوسع فيها.

لنفترض أن لغة C# لها وظيفة منشئة صريحة:

//your example
var x = new Foo( 1 );

//becomes
var x = Foo.ctor( 1 );

//your problem is valid because this would be
var x = Foo<T>.ctor<int>( 1 );
//and T can't be inferred

أنت على حق تمامًا في أنه لا يمكن استنتاج المنشئ الأول.

الآن دعنا نعود إلى الفصل

class Foo<T> 
{
    //<T> can't mean anything else in this context
    public Foo(T x) { }
}

//this would now throw an exception unless the
//typeparam matches the parameter
var x = Foo<int>.ctor( 1 );

//so why wouldn't this work?
var x = Foo.ctor( 1 );

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

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