Проблема ковариации в C#
У меня есть класс, объявленный так:
internal private abstract class BoxGroup<TS> : IBoxGroup where TS : SavedState
В этом классе у меня есть этот метод:
protected virtual TS saveState() {
return new SavedState(Width, Height);
}
Я думал, что это будет правильно, но я вижу красную линию под оператором возврата, и Решарпер говорит, что new SavedState(Width, Height)
не может быть преобразован в TS
, Я не знаю почему. я думал так TS
может быть любой класс, который расширяется SavedState
но также SavedState
сам. Что я могу сделать, чтобы исправить это?
Состояние сохраненного класса очень просто, это выглядит так:
private class SavedState {
internal float Width { get; private set; }
internal float Height { get; private set; }
public SavedState(float width, float height) {
Width = width;
Height = height;
}
}
2 ответа
Вот небольшая программа, иллюстрирующая один из возможных способов достичь желаемого:
using System;
namespace Test
{
class SaveState
{
public int Width { get; set; }
public int Height { get; set; }
}
class SaveStateWithPi : SaveState
{
public double Pi
{
get { return Math.PI; }
}
}
class Program
{
public static T CreateSavedState<T>(int width, int height)
where T : SaveState, new()
{
return new T
{
Width = width,
Height = height
};
}
static void Main(string[] args)
{
SaveState state = CreateSavedState<SaveStateWithPi>(5, 10);
Console.WriteLine("Width: {0}, Height: {1}", state.Width, state.Height);
}
}
}
По сути, идея состоит в том, чтобы использовать ограничение new() (таким образом, все ваши типы, производные от SaveState должны иметь конструктор по умолчанию) и инициализаторы объектов. Конечно, это означает, что ваш класс SaveState больше не может иметь частных сеттеров.
Это не имеет ничего общего с ковариацией; это просто невозможно.
поскольку TS
может быть любой класс, который расширяется SavedState
, вы не можете волшебным образом преобразовать базу SavedState
экземпляр к чему угодно TS
является.
Например, если я сделаю BoxGroup<MySpecialSavedState>
, твой код попробует конвертировать базу SavedState
возражать против MySpecialSavedState
, что невозможно.