代码之家  ›  专栏  ›  技术社区  ›  Matt Enright

通过构造函数链传递IDisposable对象

  •  6
  • Matt Enright  · 技术社区  · 14 年前

    我有一个小的对象层次结构,通常是从 Stream IDisposable

    代码:

    abstract class Node {
        protected Node (Stream raw)
        {
            // calculate/generate some base class properties
        }
    }
    class FilesystemNode : Node {
        public FilesystemNode (FileStream fs)
            : base (fs)
        {
            // all good here; disposing of fs not our responsibility
        }
    }
    class CompositeNode : Node {
        public CompositeNode (IEnumerable some_stuff)
            : base (GenerateRaw (some_stuff))
        {
            // rogue stream from GenerateRaw now loose in the wild!
        }
    
        static Stream GenerateRaw (IEnumerable some_stuff)
        {
            var content = new MemoryStream ();
            // molest elements of some_stuff into proper format, write to stream
            content.Seek (0, SeekOrigin.Begin);
            return content;
        }
    }
    

    我意识到 MemoryStream 这并不是一个让世界为之震惊的糟糕CLR公民身份的案例,但它仍然让我感到不安(更不用说我可能并不总是使用 内存流 Dispose () 稍后在构造函数中添加 using 中的语句 GenerateRaw () 是自我挫败,因为我需要流回来。

    先发制人的打击:

    • Node 构造函数应该是基类的一部分,并且不应该由子类计算(或者在子类中可以访问)
    • 我不要求将流传递到CompositeNode(它的格式应该与调用者无关)
    • 发电机箭头() CompositeNode 建造师。但是重复要求每个构造函数调用这个函数,却不能保证每个子类型都能运行这个函数(a) 节点 ,在语义上,如果没有初始化这些属性)会给我带来比这里的(潜在的)资源泄漏严重得多的heebie jeebies。
    4 回复  |  直到 14 年前
        1
  •  4
  •   Marc Gravell    14 年前

    CompositeNode 创建了流- 复合节点 virtual 方法将允许您这样做,但您不应该真正调用 事实上的 构造函数中的方法。

    我想知道是否重构,以便有一个 ( Load )方法(您单独调用它来构造)会更好。也许是 protected virtual public static 方法。

        2
  •  2
  •   Nicole Calinoiu    14 年前

    您可能需要考虑在接受IDisposable的构造函数的单独参数中传递关于处置的指令。这是XmlReader.Create采用的方法,它接受一个XmlReaderSettings参数,该参数的CloseInput属性确定在最终释放所创建的XmlReader时是否释放基础数据源。

        3
  •  0
  •   Simon Buchan    14 年前

    InitializeFrom(Stream s) 方法:

    abstract class Node
    {
        public Node(Stream stream) { InitializeFrom(stream); }
        protected Node() { }
        protected void InitializeFrom(Stream stream);
    }
    
    class FilesystemNode
    {
        public FilesystemNode(FileStream stream) : base(stream) {}
    }
    
    class CompositeNode
    {
        public CompositeNode(IEnumerable values) : base()
        {
            using (var stream = new MemoryStream())
            {
                // init stream
                InitializeFrom(stream);
            }
        }
    }
    

    abstract class Node
    {
        NodeKind kind;
        public Node(NodeKind kind) { this.kind = kind; }
        public NodeKind Kind { get { return kind; } }
    
        static Node ReadFrom(Stream stream);
    }
    
    class FilesystemNode : Node
    {
        string filename;
        public FilesystemNode(string filename) : Node(NodeKind.Filesystem)
        {
            this.filename = filename;
        }
        public string Filename { get { return filename; } }
    
        static FilesystemNode ReadFrom(FileStream stream);
    }
    
    class CompositeNode : Node
    {
        Node[] values;
        // I'm assuming IEnumerable<Node> here, but you can store whatever.
        public CompositeNode(IEnumerable<Node> values) : Node(NodeKind.Composite)
        {
            this.values = values.ToArray();
        }
        public IEnumerable<Node> { get { return filename; } }
    }
    
        4
  •  -1
  •   Neil Barnwell    14 年前

    主要的经验法则是,创建一次性对象实例的代码应该处理它。如果你有 IDisposable

    确保您始终这样做的一个好方法是使用 using ([IDisposable object]) { ... }

    推荐文章