0

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

我想定义一个类似这样的接口:

/// <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,而不管提供流的代码做什么。(至少,假设这些类本身被正确处理)

我该如何修改这个界面来解决这个问题?它甚至是一个可以解决的问题吗?

4

3 回答 3

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"
}

请注意该奖章的另一面:您正在提交对其他代码的引用。它可以存储它,您将不知道它们何时完成。

于 2012-08-30T00:30:36.133 回答
1

我从来没有真正喜欢关闭读取器/写入器关闭流(正是您描述的原因。)我通常通过传递读取器/写入器而不是流来解决这个问题。通常,您无论如何都想控制流的格式(文本与二进制),并且 XmlTextReader/Writer 可以从提供的 TextReader/Writer 实例化,所以现在只需决定是否为插件提供二进制或文本访问器.

于 2012-08-29T23:41:47.753 回答
0

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

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

  // etc.
}
于 2012-08-29T23:34:57.487 回答