Почему C # не поддерживает подразумеваемые универсальные типы для конструкторов классов? - PullRequest
47 голосов
/ 05 сентября 2008

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();

Это необходимо для анонимных типов, где вы не знаете, каким будет параметр типа (в intellisense он отображается как '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 # не поддерживает этот вывод универсального типа на уровне класса?

Ответы [ 3 ]

28 голосов
/ 05 сентября 2008

На самом деле, ваш вопрос неплох. Я играл с универсальным языком программирования в течение последних нескольких лет, и хотя я никогда не приходил к его разработке (и, вероятно, никогда не буду), я много думал о выводе универсальных типов, и один из моих главных приоритетов всегда было разрешено создание классов без указания универсального типа.

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);

Так как этот код на самом деле работает, мы показали, что проблема не в семантике, а в отсутствии поддержки. Я думаю, что я должен забрать мою предыдущую публикацию. ; -)

11 голосов
/ 05 сентября 2008

Почему C # не поддерживает этот вывод универсального типа на уровне класса?

Потому что они обычно неоднозначны. Напротив, вывод типов тривиален для вызовов функций (если все типы появляются в аргументах). Но в случае вызовов конструктора (прославляемые функции, для обсуждения), компилятор должен разрешать несколько уровней одновременно. Один уровень - это уровень класса, а другой - уровень аргументов конструктора. Я считаю, что решение этого алгоритмически нетривиально. Интуитивно я бы сказал, что он даже NP-завершен.

Чтобы проиллюстрировать крайний случай, когда разрешение невозможно, представьте следующий класс и скажите мне, что должен делать компилятор:

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

var x = new Foo(1);
2 голосов
/ 05 сентября 2008

Спасибо, Конрад, это хороший ответ (+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 );

Конечно, если я добавлю ваш конструктор обратно (с его альтернативным типом), мы получим неоднозначный вызов - точно так же, как если бы обычная перегрузка метода не была разрешена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...