Ограничение общего типа new() и абстрактного базового класса

Здесь у нас есть простая иерархия классов и использование дженериков с ограничением типа new()

public abstract class Base 
{
}

public class Derived : Base
{
}

public class TestClass
{
    private void DoSomething<T>(T arg) where T : new()
    {
    }

    public void TestMethod()
    {
        Derived d1 = new Derived();
        DoSomething(d1); // compiles

        Base d2 = new Derived();
        DoSomething(d2); // compile error
    }
}

Код не удается скомпилировать в указанной строке с ошибкой:

'Base' должен быть не абстрактный тип с открытым конструктором без параметров, чтобы использовать его как параметр 'T' в родовом типе или методе 'Foo.DoSomething(T)'

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

Будет ли это теоретически возможным для компилятора?

Ответ 1

Увы, вы должны явно указать тип

DoSomething<Derived>(d2);

теоретически невозможно создать нечто абстрактное

Ответ 2

новое ограничение (ссылка на С#):

Чтобы использовать новое ограничение, тип не может быть абстрактным.

Призвание:

Base d2 = new Derived();
DoSomething(d2);

Фактически вы делаете:

Base d2 = new Derived();
DoSomething<Base>(d2);

Поскольку Base является абстрактным, возникает ошибка компиляции.

Итак, вы должны явно указать:

Base d2 = new Derived();
DoSomething((Derived) d2);

Как вы могли обеспечить компилятор, чтобы кто-нибудь когда-либо там что-то помещал, а не абстрактно?

Единственный способ, который я вижу, будет, если бы мы получили ключевое слово как "must-inherit-to-non-astract", а затем создали public must-inherit-to-non-abstract abstract class Base. После этого компилятор может быть уверен, что если вы поместите базовый экземпляр в свой метод, это будет фактически подклассом, который не является абстрактным и поэтому может быть создан.