Чому в C # є нове () обмеження, але немає іншого подібного обмеження?


19

У C # generics ми можемо оголосити обмеження для параметра типу, Tщоб мати конструктор за замовчуванням, сказавши where T : new(). Однак ніякі інші види таких обмежень не є дійсними - new(string)наприклад, тощо.

Що з мовної розробки та / або впровадження, що є причиною цього?

Чи є щось у тому, як працюють конструктори чи в тому, як реалізується система типів, що забороняє це (або принаймні ускладнює)? Якщо так, то що це? Пригадую, я читав десь, що default(T)насправді збирається new T()для T : struct. Чи пов’язано це з цим, можливо?

Або це просто дизайнерське рішення, прийняте для того, щоб уникнути ускладнення мови?


new(string)не є обмеженням конструктора за замовчуванням. Ваше запитання рівнозначне: "Чому не існує обмежень, які вимагають конкретних підписів конструктора?" Дуже ймовірно, оскільки таке обмеження не було б особливо корисним.
Роберт Харві

3
@RobertHarvey Так, це саме те, що я говорю. Я, по суті, запитую, чи є щось, що робить конструктори за замовчуванням особливою реалізацією, чи це був просто довільний вибір для включення цього, а не іншого.
Теодорос Чатзіґананакіс

Конструктори за замовчуванням корисні певними, важливими, способами. Наприклад, вони роблять тип легко серіалізаційним.
Роберт Харві

6
Конкретні підписи ctor можуть бути корисними. Наприклад, якщо ваша змінна типу обмежена колекцією <T> з ctor T (Колекція <T>), ви знаєте, що ви можете створити нові колекції, надані іншим. Чи варта ця корисність додаткової складності - питання.
Phoshi

Відповіді:


5

Для авторитетної відповіді я б посилав вас на відповідь Еріка Ліпперта на це запитання в StackOverflow кілька років тому, фрагмент якого коротко цитується нижче.

Однак у цьому конкретному випадку я, безумовно, можу навести вам декілька причин, чому я б наштовхнувся на цю функцію, якщо вона з’явилася на зустрічі дизайнерів як можлива функція для майбутньої версії мови.

...

Я кажу, що ми повинні або робити всю функцію, або не робити це взагалі. Якщо важливо вміти обмежувати типи, щоб мати конкретні конструктори, то давайте зробимо всю функцію та обмежимо типи на основі членів взагалі, а не лише конструкторів.


2
Ця цитата, виведена з контексту, є дуже оманливою. Це говорить про те, що Ерік вважав, що Microsoft повинен був "пройти весь шлях", що зовсім не є його позицією. Насправді він категорично проти запропонованої функції.
Роберт Харві

1
Дякую, це справді відповідає на моє запитання частково: Наприкінці своєї відповіді Ерік Ліпперт зазначає, що обмеження ІЛ та включення цієї функції вимагатиме доповнення до ІЛ. Було б ідеально , якщо б ви могли надати джерело про те , що генерується IL для тієї частини , яка буде реалізована - тобто, в загальному , виклик конструктора за замовчуванням.
Теодорос Чатзіґананакіс

@TheodorosChatzigiannakis: Чому ти не запустиш Decompiler Telerik і не дізнаєшся сам?
Роберт Харві

2
@RobertHarvey Я не думаю, що це взагалі пропонує йому позицію, але я включив додаткову цитату, щоб підкреслити його позицію.
Кріс Ханнон

1
Хм, у F # є більш попередні способи обмеження типу , наприклад, перевірка часу компіляції, якщо клас має оператора. Можливо, F # потребує більш потужної системи обмежень, ніж C # через дуже сувору перевірку типу. Тим не менш, ця мова здатна реалізувати сучасні способи утримання класу в .Net Framework.
OnesimusUnbound

16

Декомпіляція (за пропозицією Роберта Харві) дала наступне для всіх, хто зацікавився. Цей спосіб:

static T GenericMake<T>()
    where T : new()
{
    return new T();
}

Мабуть, коли компілюється, стає таким:

private static T GenericMake<T>()
    where T : new()
{
    T t;
    T t1 = default(T);
    if (t1 == null)
    {
        t = Activator.CreateInstance<T>();
    }
    else
    {
        t1 = default(T);
        t = t1;
    }
    return t;
}
  • Якщо Tце значення типу, new()стає default(T).
  • Якщо Tє еталонним типом, new()працює за допомогою відображення. Activator.CreateInstance()внутрішньо дзвінки RuntimeType.CreateInstanceDefaultCtor().

Отож, це - внутрішньо, конструктори за замовчуванням справді є особливими для C # по відношенню до CLR. Надання іншим конструкторам такого ж лікування було б дорогим, навіть якщо є деякі дійсні випадки використання для складніших обмежень у генериці.


4
Цікаво. Чому дублікат викликає default(T) для типів значень?
Авнер Шахар-Каштан

2
@ AvnerShahar-Kashtan я не знаю. Це може бути артефакт процесу компіляції / декомпіляції, як і tзмінна (яка може бути замінена вкладеними returnоператорами).
Теодорос Чатзіґананакіс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.