gpt4 book ai didi

c# - SslStream.ReadAsync 从不调用 InnerStream.ReadAsync

转载 作者:行者123 更新时间:2023-11-30 19:15:57 27 4
gpt4 key购买 nike

我不确定我是否遗漏了什么或者 SslStream 中确实存在设计缺陷(可能还有其他可以包装内部流的流类)。

考虑这个伪代码:

MyStream
{
Task<int> ReadAsync()
{ ... }
}

...

{
MyStream my = new MyStream();
SslStream ssl = new SslStream(my);
ssl.ReadAsync(...);
}

尽管人们可能期望 SslStream.ReadAsync 最终会调用 MyStream.ReadAsync,但事实并非如此。相反,它会调用 MyStream.BeginRead(如果已定义)。如果未定义 MyStream.BeginRead,则行为将难以预测(这将取决于 MyStream 派生自哪个类等等)。

简而言之,要使 SslStream 的异步/等待方法按预期工作,需要实现内部流类的 BeginXXX/EndXXX(非异步/等待方法)。

BeginXXX/EndXXX 模式对于开发来说比异步/等待模式复杂得多(对我来说,这就是引入异步/等待的原因——让异步编程更容易)。但是仍然开发 BeginXXX/EndXXX 方法的要求违背了 async/await 的目的。

此外,还需要了解 SslStream 类的内部实现(因为如果实现不同,它可以直接调用 InnerStream.ReadAsync)。我的意思是 SslStream 的公共(public)签名没有清楚地为我提供足够的信息,说明我是否应该在我的内部流类中实现 ReadAsync 或 BeginRead。

为此,我需要使用试错法或检查 SslStream 的源代码(及其 Stream 父级,因为 SslStream 从基本 Stream 类继承 ReadAsync)。这似乎不是一种可靠且直接的代码编写方式。

当前在 SslStream/Stream 类中实现 ReadAsync 等异步/等待方法是否有原因?

最佳答案

是的,特别是 Stream 有点乱,因为它早在 async/await 之前就存在了。例如,ReadAsync 的默认实现实际上会在线程池线程上进行阻塞读取。

我建议您将 ReadAsync 重写为常规 TAP 方法,并将 BeginRead/EndRead 重写为该 TAP 方法的 APM 包装器。 MSDN docs对此有最好的模式(正确处理 callbackstate),除了我更喜欢对它们进行一些调整,这样 EndRead 的任何异常都不会包装在 AggregateException 中:

public static IAsyncResult ToBegin<T>(
Task<T> task, AsyncCallback callback, object state)
{
var tcs = new TaskCompletionSource<T>(state);
task.ContinueWith(t =>
{
if (t.IsFaulted) tcs.TrySetException(t.Exception.InnerExceptions)
else if (t.IsCanceled) tcs.TrySetCanceled();
else tcs.TrySetResult(t.Result);

if (callback != null) callback(tcs.Task);
}, TaskScheduler.Default);
return tcs.Task;
}

public static T ToEnd<T>(IAsyncResult result)
{
// Original MSDN code uses Task<T>.Result
return ((Task<T>)result).GetAwaiter().GetResult();
}

关于c# - SslStream.ReadAsync 从不调用 InnerStream.ReadAsync,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30372241/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com