为什么我的非关闭流仍然关闭

  • 本文关键字: c# serialization stream
  • 更新时间 :
  • 英文 :


我有一个非关闭流类,它被包装在一个带有二进制读取器的using块中,但由于某种原因,当块结束时,我的非关闭流仍然关闭。

流定义为:

internal class NonClosingStream : Stream, IDisposable
{
    private Stream baseStream;
    public NonClosingStream(Stream baseStream)
    {
        this.baseStream = baseStream;
    }
    public override bool CanRead{ get { return baseStream.CanRead; } }
    public override bool CanSeek{ get { return baseStream.CanSeek; } }
    public override bool CanWrite { get { return baseStream.CanWrite; } }
    public override void Flush()
    {
        baseStream.Flush();
    }
    public override long Length { get { return baseStream.Length; } }
    public override long Position
    {
        get { return baseStream.Position; }
        set { baseStream.Position = value; }
    }
    public override int Read(byte[] buffer, int offset, int count)
    {
        return baseStream.Read(buffer, offset, count);   
    }
    public override long Seek(long offset, SeekOrigin origin)
    {
        return baseStream.Seek(offset, origin);
    }
    public override void SetLength(long value)
    {
        baseStream.SetLength(value);
    }
    public override void Write(byte[] buffer, int offset, int count)
    {
        baseStream.Write(buffer, offset, count);
    }
    public override void Close()
    {
        // Disconnects from base stream, but does not close it
        this.baseStream = null;
    }
    void IDisposable.Dispose()
    {
        // Disconnects from base stream, but does not close it
        this.baseStream = null;
    }
}

读取块如下所示:

public T Deserialize<T>(Stream stream)
{
    using (NonClosingStream nonClosingStream = new NonClosingStream(stream))
    using (BinaryReader reader = new BinaryReader(nonClosingStream, Encoding.ASCII, true))
    {
        // Read the type name, then convert it to an actual type
        String typeName = reader.ReadString();
        Type graphType = AvailableTypes.GetType(typeName);
        // If a deserializer for this type already exists, use it.
        if (deserializerFunctions.ContainsKey(graphType))
        {
            return (T)deserializerFunctions[graphType](reader);
        }
        // Otherwise, create one and use it
        T graph = (T)FormatterServices.GetUninitializedObject(graphType);
        typeof(ServiceSerializer).GetMethod("DeserializeObject",
                BindingFlags.NonPublic | BindingFlags.Static)
            .MakeGenericMethod(graphType)
            .Invoke(this, new Object[] { reader, graph });
        return graph;
    }
}

我做错了什么?

更新

所以我写了一个小笑话:

static void Main()
{
    MemoryStream stream = new MemoryStream();
    using (NonClosingStream nonCloser = new NonClosingStream(stream))
    using (BinaryWriter writer = new BinaryWriter(nonCloser))
    using (BinaryReader reader= new BinaryReader(nonCloser))
    {
        writer.Write("Lorem ipsum");
        stream.Seek(0, SeekOrigin.Begin);
        String data = reader.ReadString();
        Console.WriteLine(data);
    }
    stream.Seek(0, SeekOrigin.Begin);
    using (NonClosingStream nonCloser = new NonClosingStream(stream))
    using (BinaryWriter writer = new BinaryWriter(nonCloser))
    using (BinaryReader reader = new BinaryReader(nonCloser))
    {
        writer.Write("Lorem ipsum");
        stream.Seek(0, SeekOrigin.Begin);
        String data = reader.ReadString();
        Console.WriteLine(data);
    }
    Console.ReadLine();
}

它似乎运行得很好,水流保持正常。所以我想共识是正确的。不知怎么的,我正在关闭其他地方的小溪。当我弄清楚结果后,我会发布结果。谢谢大家。

更新

啊啊,我解决了问题。因此,代码的工作方式是,当它序列化/反序列化对象时,它会用表达式树构建一个自定义的序列化程序,然后对其进行编译,以便将来的序列化更加流畅。这意味着我的代码到处都是这样的东西:

Action<BinaryReader, Object> assignmentAction = delegate(BinaryReader bReader, Object oGraph)
{
    bReader.ReadByte();      // Read the next action
    bReader.ReadString();    // Read the field name
    bReader.ReadByte();      // Read the field type
    // Call the assignment lambda
    assignmentLambda(reader, deserializerFunctions[primitiveType], (T)oGraph);
};

你抓到了吗?不我显然也没有。让我们添加一些上下文:

private static void DeserializeObject<T>(BinaryReader reader, T graph)
{
    ...
    Action<BinaryReader, Object> assignmentAction = delegate(BinaryReader bReader, Object oGraph)
    {
        bReader.ReadByte();      // Read the next action
        bReader.ReadString();    // Read the field name
        bReader.ReadByte();      // Read the field type
        // Call the assignment lambda
        assignmentLambda(reader, deserializerFunctions[primitiveType], (T)oGraph);
    };
    ...
}

lambda从外部块关闭reader,而不是使用缓存的反序列化程序运行时提供的bReader。因此,当反序列化程序运行时,它使用的是一个已经丢弃的二进制读取器对象,而不是提供给它的新对象。我想问题不在于我关闭了流,而是我使用了一个已丢弃的读取器。至少这解释了为什么它会工作一次,然后第二次失败,因为第二次它依赖于缓存的反序列化程序。哎呀!

谢谢大家。

由于您的流没有创建内部流,因此外部代码很可能会关闭您的内部流。你的代码可能看起来像:

 NonClosingStream nonClosing;
 using(var stream = new FileStream(...))
 {
   nonClosing = new NonClosingStream(stream );
  ....
 } 
 // inner stream now closed and nonClosing will fail all operations.
void IDisposable.Dispose()

您的类有两个Dispose((方法。您明确实现的。以及您从Stream类继承的那个。问题是,BinaryStream不了解您的bean。它只知道Stream实现的那个。此外,当您使用BinaryStream(Stream(构造函数时,BinaryStream对象将承担所传递Stream对象的所有权。这意味着它将在自己被处理时处理该流。也许您现在看到了问题,继承的Dispose((方法将被调用,而不是您的方法。它关闭了基本流。

这就是Stream实现Dispose模式的原因。你需要让它看起来像这样:

internal class NonClosingStream : Stream {
    protected override Dispose(bool disposing) {}
}

这取决于NonClosingStream类包装的流是否在其他地方被引用。如果没有,那么底层流将没有引用,因此在之后的某个时刻,它的终结器将关闭流。

相关内容

  • 没有找到相关文章

最新更新