Это мой ковариантный интерфейс с одним возвращаемым и перечислимым методом, который также ковариантен (как всегда).Простой.
public interface IDataSource<out TData> {
IAsyncEnumerable<TData> StreamData(CancellationToken cancellationToken = default);
}
Теперь я хочу добавить больше данных к этому перечислимому, используя ValueTuple
:
public interface IDataSource<out TData> {
IAsyncEnumerable<(TData data, DateTime timestamp)>> StreamData(CancellationToken cancellationToken);
}
Теперь я получаю ошибку компилятора о том, что TData data
должен быть инвариантно действительным.Я вижу, ValueTuple
не является ковариантным.
Хорошо, тогда я просто сверну свой особый кортеж, так как я действительно хочу иметь возможность использовать этот красивый синтаксис деконструкции в foreach
позже:
public interface IDataSource<out TData> {
IAsyncEnumerable<IDataTuple<TData>> StreamData(CancellationToken cancellationToken);
}
public interface IDataTuple<out TData> {
void Deconstruct(out TData data, out DateTime timestamp);
}
Но компилятор все равно говорит "нет".Это приводит к той же ошибке, теперь на out TData data
.
Хорошо, компилятор, вы, что вы думаете об этом:
public interface IDataSource<out TData> {
IAsyncEnumerable<IDataTuple<TData>> StreamData(CancellationToken cancellationToken = default);
}
public interface IDataTuple<out TData> {
TData Data { get; }
DateTime Timestamp { get; }
}
public static class DataTupleExtensions {
public static void Deconstruct<TData>(this IDataTuple<TData> tuple, out TData data, out DateTime timestamp) {
data = tuple.Data;
timestamp = tuple.Timestamp;
}
}
public async Task StreamData<TData>(IDataSource<TData> dataSource, CancellationToken cancellationToken = default) {
await foreach (var (data, timestamp) in dataSource.StreamData(cancellationToken)) {
// Do stuff
}
}
Это компилируется и работает какочарование.Но почему? В чем разница между объявлением Deconstruct
как метода расширения, а не как метода интерфейса? Где начинается ковариация и начинается инвариантность?
И, кроме того, не должноout
параметры будут ковариантно действительными? Я имею в виду, это буквально одно и то же ключевое слово.Это имело бы смысл для меня.