我有一个非关闭流类,它包含在带有二进制阅读器的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();
}
它似乎工作正常,流保持开放,就像它应该的那样。所以我认为共识是正确的。不知何故,我正在其他地方关闭流。当我弄清楚我会发布什么结果。谢谢大家。
更新
Gaaaahhh,我发现了问题所在。因此代码的工作方式是,当它对一个对象进行序列化/反序列化时,它会从表达式树中构建一个自定义的序列化程序,然后对其进行编译,以便将来的序列化更加流畅。这意味着我的代码充满了这样的东西:
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
。因此,当解串器运行时,它使用已经丢弃的二进制读取器对象而不是提供给它的新对象。我想问题不在于我关闭了流,而是我正在使用一个处理过的读者。至少这解释了为什么它会工作一次,然后第二次失败,因为它第二次依赖于缓存的反序列化器。糟糕!
谢谢大家。
答案 0 :(得分:1)
由于您的流不会创建内部流,因此很可能外部代码会关闭您的内部流。您的代码可能是:
NonClosingStream nonClosing;
using(var stream = new FileStream(...))
{
nonClosing = new NonClosingStream(stream );
....
}
// inner stream now closed and nonClosing will fail all operations.
答案 1 :(得分:1)
void IDisposable.Dispose()
您的课程有两个 Dispose()方法。你明确实施的那个。而你从Stream类继承的那个。问题是,BinaryStream不知道关于你的bean。它只知道Stream实现的那个。此外,当您使用BinaryStream(Stream)构造函数时,BinaryStream对象将承担传递的Stream对象的所有权。这意味着当它自己处理时它将处理该流。也许您现在看到问题,将调用继承的Dispose()方法,而不是您的方法。它关闭了基本流。
这就是Stream实现Dispose模式的原因。你需要让它看起来像这样:
internal class NonClosingStream : Stream {
protected override Dispose(bool disposing) {}
}
答案 2 :(得分:0)
这取决于NonClosingStream类包装的流是否在其他地方引用。如果没有,那么底层流将没有引用,所以在某些时候它的终结器将关闭流。