从 .net core 2.1 与 .net core 3.0 调用时的 StreamWriter 类行为

Posted

技术标签:

【中文标题】从 .net core 2.1 与 .net core 3.0 调用时的 StreamWriter 类行为【英文标题】:StreamWriter class behavior when call from .net core 2.1 vs .net core 3.0 【发布时间】:2020-10-27 20:09:22 【问题描述】:

我在 .net 标准 2.0 中编写了一个 dll。假设只是通过StreamWriter将数据写入文本文件。

注意:我知道下面的代码可以用更好的方式编写。此代码只是测试库。

DLL 代码:

public class WriteIntoLog
    
        private StreamWriter _streamWriter;
        public void WriteMsgToFile(string message)
        
            try
            
                bool close = true;

                if (_streamWriter == null || _streamWriter.BaseStream == null)
                    _streamWriter = new StreamWriter("Test.txt", true);

                _streamWriter.WriteLine(message);

                if (close)
                    CloseLogFileStream(false);
            
            catch (IOException ioEx)
            
                throw new Exception(ioEx.Message);
            
            catch (Exception ex)
            
                throw new Exception(ex.Message);
                          
        
        public void CloseLogFileStream(bool dispose)
        
            if (_streamWriter != null)
            
                _streamWriter.Close();
                if (dispose)
                    _streamWriter = null;
            

        
    

并从.net core 2.1编写的控制台应用程序调用此dll

class TStreamWriter
    
        static void Main(string[] args)
        
            WriteIntoLog log = new WriteIntoLog();

            for (int i = 0; i < 10; i++)
            
                log.WriteMsgToFile($"Loop no: i.ToString()");
            
                        
            Console.WriteLine("Hello World!");
        
    

现在此代码按预期运行,但是当我将控制台应用程序的目标平台更改为 .net core 3.0 时,代码返回“无法写入已关闭的 TextWriter”的异常。

那么为什么它在.net core 2.1 中运行控制台应用程序时不返回异常。

【问题讨论】:

没有区别。 WriteIntoLog 虽然有问题,但无论它是否存在,都会使用相同的 cached 流。鉴于WriteMsgToFile 之外不需要此流,因此没有理由将其存储在字段中 为什么要编写自己的日志记录代码,而不是使用像 Serilog 或 .NET Core 自己的 Microsoft.Extensions.Logging 这样的库? 顺便说一句,你可以用File.AppendAllText(somePath,message + "\n");替换所有这些代码 @PanagiotisKanavos 存在一些差异,因为相同的代码在 2.1 中运行良好,而在 3.0 中出现异常。 并非如此 - 实例已被处置,已死亡,不打算再次使用。事实上,我很惊讶当您尝试访问 BaseStream 时却没有收到 ObjectDisposedException 【参考方案1】:

问题是您正在创建WriteIntoLog 的实例,然后多次调用它的函数。第一次之后,由于bool close 始终是true,因此在流上调用Close()。未来的循环迭代 (2 - 10) 尝试使用关闭的流进行写入,因为 _streamWriter 已关闭并且此代码将不再评估为 true:

if (_streamWriter == null || _streamWriter.BaseStream == null)
                _streamWriter = new StreamWriter("Test.txt", true);

【讨论】:

都是正确的,但是并没有说明两个目标框架的区别。 @Maarten 没有调查过,但我几乎可以保证,一旦流关闭,_streamWriter.BaseStream 在核心 2.1 中为空,在 3.0 中不为空 不错,确实是这样。 @Haney 你是对的。 _streamWriter.BaseStream 在 3.0 中不为空。这意味着两个版本中StreamWriter类的实现存在差异 @vikky 为什么要写这样的代码?它是一个已处置的类,绝对不能保证它的成员(如 BaseStream)会处于一种或另一种状态。【参考方案2】:

您遇到问题是因为 _streamWriter 已关闭,但不是 null

你可以简单地做到这一点。

using (StreamWriter write = new StreamWriter(""))

...//Add your code here

【讨论】:

这里没有说明两个目标框架的区别。 @Maarten 框架没有区别。 OP 使用错误代码 并且 尝试通过 BaseStream 触及实现细节。无法保证 disposed writer 的流会处于一种或另一种状态 @Maarten 我同意,但这发生在代码中的错误上。所以如果我们解决了这个问题,他就不会遇到这样的错误。

以上是关于从 .net core 2.1 与 .net core 3.0 调用时的 StreamWriter 类行为的主要内容,如果未能解决你的问题,请参考以下文章

从 .NET Core 2.1 降级到 .NET 4.7.1 时如何使用 IApplicationBuilder 和 IServiceCollection?

ASP.NET Core 2.1 中的 HttpClientFactory (Part 3) 使用Handler实现传出请求中间件

从asp.net core 2.1中的控制器访问BackgroundService

ZXing QrCode 渲染器异常与 .Net Core 2.1

直接从令牌获取 JWT 声明,ASP Net Core 2.1

.Net Core 2.1 过期的 JWT 令牌响应 [发布与获取]