有没有办法将流传递给某个外部组件,同时保持对该流的所有权?

时间:2012-08-29 23:24:41

标签: c# .net stream filestream

我有一个读取特定文件格式的应用程序。此外,该应用程序支持读取备用文件格式的“插件”,并将其转换为该工具本身支持的标准化格式。

我想定义一个类似这样的界面:

/// <summary>
/// Interface for file transformer. Implementers of this interface provide a means to
/// convert a given file into Foo Format.
/// </summary>
public interface IFileTransformerPlugin
{
    /// <summary>Gets the name of the transformer to display to the user.</summary>
    /// <value>The name of the transformer displayed to the user.</value>
    string DisplayName
    {
        get;
    }

    /// <summary>Determines if this transformer can handle the given format.</summary>
    /// <remarks>
    /// This method should return very quickly; reading only a small portion of the
    /// input stream. This method is intended to be a rough cut check -- returning true
    /// does not necessarily mean that the file will parse successfully on full load.
    /// </remarks>
    /// <param name="fileContents">The file contents.</param>
    /// <returns>
    /// true if this transformer can handle the supplied format, false otherwise.
    /// </returns>
    bool CanHandleLogFormat(Stream fileContents);

    /// <summary>Transforms a file into Foo Format.</summary>
    /// <param name="inputFile">The input log stream.</param>
    /// <param name="outputFile">The output log stream (where the output should be
    /// written).</param>
    /// <returns>A transformation result which includes error information.</returns>
    LogTransformationResult Transform(Stream inputFile, Stream outputFile);
}

问题来自采用流的转换方法。从概念上讲,我希望插件主机而不是插件“拥有”这些流,并负责调用IDispose或这些流上的任何内容。例如,在测试场景下,调用者可以将MemoryStream作为输出传递,然后验证输出是否有效。

但是,作为插件作者,希望能够在框架中使用上层格式化构造;即TextReader / TextWriter;的XmlTextReader / XmlTextWriter的;但是这些类获取底层流的所有权并在底层流上调用Dispose,而不管提供流的代码是什么。 (至少,假设这些类本身被正确处理)

我如何重写此界面以解决此问题?它甚至是一个可以解决的问题吗?

3 个答案:

答案 0 :(得分:3)

这引用了经典的软件工程线:“每个问题都可以通过额外的间接层来解决”。只需包装流并提供委托给基本流的单行方法。除了Dispose方法之外,什么也不做,这样无论客户端代码做什么,你都可以控制流。像:

public class OwnedStream : Stream {
    private Stream stream;
    public OwnedStream(Stream stream) { this.stream = stream; }
    protected override void Dispose(bool disposing) {
        // Do nothing
    }
    public override bool CanRead { get { return stream.CanRead; } }

    // etcetera, just delegate to "stream"
}

请注意该奖章的另一面:您正在处理对其他代码的引用。它可以存储它,你不知道什么时候完成它。

答案 1 :(得分:1)

我从来没有真正喜欢关闭读者/作者关闭流(正是你描述的原因。)我通常通过传递读者/作者而不是流来解决这个问题。通常你想控制流的格式(文本与二进制),XmlTextReader / Writer可以从提供的TextReader / Writer中实例化,所以现在只需要决定你是否给你的插件一个二进制或文本访问器

答案 2 :(得分:0)

为什么不通过界面中的getter访问流对象?然后,您的应用程序可以在需要时从实现中获取流引用。

public interface IFileTransformerPlugin {
  string DisplayName { get; }
  string Stream inputFile { get; }

  // etc.
}