Спрашивал на разных ресурсах, в последней инстанции тут
https://github.com/dotnet/docs/issues/25233 дали ответ, но это догадки и они неубедительны.
Вопрос:
Как я понимаю, ключевые слова in и out в универсальных вариантных делегатах нужны только чтобы назначить один делегат другому. Для назначения методов вариантность есть и без ключевых слов in и out.
Источник https://docs.microsoft.com/ru-ru/dotnet/csharp/pro...
Цитата:
Если поддержка вариантности используется только для сопоставления сигнатур методов с типами делегатов, а ключевые слова in и out не используются, можно создать экземпляры делегатов с одинаковыми лямбда-выражениями или методами, но нельзя назначить один делегат другому.
Почему я не могу сделать то же самое (назначать только методы), но через универсальный вариантный интерфейс? И мне приходится писать в объявлении делегата ключевое слово (in или out).
Например,
namespace ConsoleApp1 {
class Program {
static void Main(string[] args) {
//Шаг 1
B MyMethodReturnB() {
return new B();
}
//Шаг 2
MyClass<A> MyClassForA = new MyClass<A> ();
MyClassForA.MyEvent += MyMethodReturnB; //В MyClass< A >() вы можете поместить данные типа B с помощью метода MyMethodReturnB и без ключевого слова out в делегате MyDelegateReturn
//Шаг 3
MyDelegateReturn<B> MyDelegateReturnForB = new MyDelegateReturn<B>(MyMethodReturnB);
//MyClassForA.MyEvent += MyDelegateReturnForB; //Но когда мы пытаемся передать данные типа B через переменную делегата без ключевого слова out, возникает ошибка, так вариантность работает в делегатах.
//Без ключевых слов in и out один делегат не может быть назначен другому делегату
//Шаг 4
IMyInterface<B> IMyInterfaceForB = MyClassForA; //Через интерфейс IMyInterface< B > без ключевого слова in вы не можете поместить MyClass< A >(), но если IMyInterface< B > с ключевым словом in, то мы можем
//Шаг 5
//Как только мы создадим интерфейс с ключевым словом in, потребуется делегат с ключевым словом out, почему?
//В конце концов, delagate без ключевого слова out каким-то образом имеет ковариацию, но только для методов, а не экземпляров делегата, что означает, что я мог бы в любом случае поместить метод в событие, но не экземпляр делегата. Но мы не можем этого сделать
}
}
class A {
}
class B: A {
}
delegate T MyDelegateReturn</*out*/ T>(); //С ключевым словом out все работает
interface IMyInterface<in T>{
event MyDelegateReturn<T> MyEvent; //Ошибка из-за делегата без ключевого слова out
}
class MyClass<T>: IMyInterface<T> {
public event MyDelegateReturn<T> MyEvent;
}
}