Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/290.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用扩展方法将协变接口解构为值元组时的奇怪行为_C#_Tuples_Covariance_Variance_Valuetuple - Fatal编程技术网

C# 使用扩展方法将协变接口解构为值元组时的奇怪行为

C# 使用扩展方法将协变接口解构为值元组时的奇怪行为,c#,tuples,covariance,variance,valuetuple,C#,Tuples,Covariance,Variance,Valuetuple,这是我的协变接口,其中有一个方法返回且可枚举,该方法也是协变的(一如既往)。简单 现在我得到一个编译器错误,指出TData数据必须是不变有效的。我明白了,ValueTuple不是协变的 好的,那么我将滚动我自己的非常特殊的元组,因为我真的希望能够在以后的foreach中使用好的解构语法: public interface IDataSource<out TData> { IAsyncEnumerable<IDataTuple<TData>> Stre

这是我的协变接口,其中有一个方法返回且可枚举,该方法也是协变的(一如既往)。简单

现在我得到一个编译器错误,指出
TData数据
必须是不变有效的。我明白了,
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参数不应该是协方差有效的吗?我的意思是,它实际上是同一个关键字。这对我来说是有意义的。

@DavidG有趣的是,在纯C#
中,out
参数可以是协变的,但是CLR的内部结构以及与其他.Net语言的兼容性使得它不可能实现,而且它们也被禁止。这至少解决了
out
参数的谜团。谢谢,先生。@BrunoZell有趣的是,在纯C中,out参数可以与引用的问题共变,这表明
out
参数在纯C中也不能共变。
public interface IDataSource<out TData> {
    IAsyncEnumerable<(TData data, DateTime timestamp)>> StreamData(CancellationToken cancellationToken);
}
public interface IDataSource<out TData> {
    IAsyncEnumerable<IDataTuple<TData>> StreamData(CancellationToken cancellationToken);
}

public interface IDataTuple<out TData> {
    void Deconstruct(out TData data, out DateTime timestamp);
}
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
    }
}