我有一个读取特定文件格式的应用程序。此外,该应用程序支持读取备用文件格式的“插件”,并将其转换为该工具本身支持的标准化格式。
我想定义一个类似这样的界面:
/// <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,而不管提供流的代码是什么。 (至少,假设这些类本身被正确处理)
我如何重写此界面以解决此问题?它甚至是一个可以解决的问题吗?
答案 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.
}