Проблема Contra / Covariance при назначении для Lazy <> - PullRequest
0 голосов
/ 25 июня 2018
private void AMethod<T>() where T : Control, new()
{
    Lazy<T> lazyControl = new Lazy<T>(() => new T());

    Lazy<Control> a = lazyControl;
}

В последней строке я получаю следующую ошибку.

Argument 2: cannot convert from 'System.Lazy<T>' to
'System.Lazy<System.Windows.Forms.Control>'

Я понимаю, что T может быть более конкретным типом, но я не понимаю, почему не могу присвоить егоЛенивая переменная.

Ответы [ 2 ]

0 голосов
/ 25 июня 2018

Если бы существовал интерфейс ILazy<T>, он мог бы быть объявлен как ILazy<out T>, и все было бы хорошо в вашем примере: T - это , эффективно используемое только в выходной позиции.

Однако Lazy<T> - это класс.Ковариантность / контравариантность можно указывать только для делегатов и интерфейсов, поэтому Lazy<T> не может указать ее ковариацию.

Поэтому Lazy<Control> несовместим с Lazy<T>, поэтому назначение не работает.Это определенно расстраивает, учитывая, что, по крайней мере, с текущим API, было бы «безопасно», чтобы он был ковариантным, с точки зрения вызывающего.

(Если вам нужно это повсеместно, вы можете объявитьсобственный интерфейс ILazy<out T>, а затем написать реализацию этого интерфейса для переноса Lazy<T>. Я подозреваю, что это больше проблем, чем оно того стоит.)

0 голосов
/ 25 июня 2018

Я понимаю, что T может быть более конкретным типом, но я не понимаю, почему я не могу присвоить его переменной Lazy.

A Lazy<T>не имеет отношения с Lazy<Control>, точно так же, как Lazy<Base> имеет какие-либо отношения с Lazy<Derived>.

Просто потому, что Derived происходит от Base, и вы можете сделать это:

Base b = new Derived();

... это не значит, что вы можете сделать это:

Lazy<Base> b = new Lazy<Derived>();

Тип Lazy<Derived> не является производным от Lazy<Base>.@Jon Skeet хорошо объясняет это здесь:

Проблема дисперсии C #: назначение списка как списка

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