存储对构造函数初始化程序中创建的对象的引用

时间:2011-10-06 11:46:37

标签: c# constructor

摘要:如果我在构造函数初始化程序中创建对象,如何保留对它的引用,以便稍后引用它?

详情

我有一个类(LibBase,下面),需要StreamWriter作为其构造参数。我没有LibBase的源代码 - 它在第三方库中。

public class LibBase
{
    public LibBase(System.IO.StreamWriter wtr) { ... }
}

我从MyClass派生了LibBase,在MyClass构造函数中,我想将MyWriter的实例(派生形式StreamWriter)传递给基础类。我这样做如下。

public class MyWriter : System.IO.StreamWriter
{
    public MyWriter(int n) { ... }
    // Contains unmanaged resources
}

public class MyClass : LibBase
{
    public MyClass(int n)
    : LibBase(new MyWriter(n))
    { }
}

问题是MyWriter需要处置,因此MyClass应该处置它(并实施IDisposable来执行此操作)MyClass没有引用创建的MyWriter实例,所以我无法处理它。构造函数初始化程序的语法似乎不允许我保留引用。

我的解决方案是重新编码MyClass,如下所示:

public class MyClass : LibBase, IDisposable
{
    public MyClass(Encoding enc)
    : this(new MyWriter(enc))
    { }

    private MyClass(MyWriter wtr)
    : LibBase(wtr)
    { this.wtr = wtr; }  // store reference

    private MyWriter wtr;

    // (implement IDisposable using wtr member variable
}

私有构造函数存储对MyWriter实例的引用,以便稍后处理它。

我的问题

  1. 我在这里失踪了什么?我觉得我在和语言作斗争。 C#是否提供了更好的方法?
  2. 如果语言不直接支持这个,那么有没有比我的私有构造函数更好的解决方案?
  3. 对我的解决方案中的缺陷有何评论?

3 个答案:

答案 0 :(得分:5)

我不认为你在这里遗漏任何东西。您的解决方案对我来说没问题如果 LibBase真的不能让您获得传递给构造函数的作者。

我怀疑没有更明确支持的原因是它不会经常出现。如果您发现它在设计中经常出现,那么可能您过度使用继承。

channel Eric Lippert

  

然而,正如我经常指出的那样,我没有必要提供不做功能的理由。功能不便宜;它们非常昂贵,而且它们不仅要证明自己的成本是合理的,而且必须证明没有完成我们本可以用这个预算完成的其他一百个功能的机会成本。我们必须证明我们的利益相关者的功能成本合理,但我们不需要通过不实现不符合我们标准的功能来节省时间和精力。

我的猜测这是不符合标准的东西,即使它首先被认为是可取的。 (C#团队的成本超出了成本 - C#开发人员承担了每个功能的精神成本,并且每个新功能的持续成本使得添加 next 功能更加困难。 )

答案 1 :(得分:2)

你的解决方案似乎没问题......我认为你不会错过任何东西......

如果您想要更改实施(无论出于何种原因):

  • 您可以通过不继承LibBase但将实例作为私人成员来实现...
  • 另一种选择是实现MyClass的工厂模式,因此没有公共构造函数并创建StreamWriter实例工厂端等。

但正如我所说,解决方案没有任何问题(如果经常发生,你可能应该重新考虑你的设计)。

编辑 - 根据评论:

“创建StreamWriter工厂端”的意思是:为MyClass创建一个工厂,以便任何需要实例的人都使用工厂...在其中您可以创建StreamWriter实例工厂方法并将其作为参数传递给MyClass ...这样你甚至可以实现一些奇特的东西,比如“MyClass实例正在使用给定的StreamWriter实例?”或MyClass / StreamWriter个实例等的某种缓存。

答案 2 :(得分:1)

我认为在这种情况下,您不应该派生LibBase而是委托给它。在这种情况下,您显然可以按任何顺序初始化成员。

任何处理MyClass的人都必须处理,但编写使用LibBase的代码不会,因此您不能简单地将MyClass的实例放在编写为处理{的代码中{1}}。在这种情况下,继承并不合适。当然,如果LibBase兼作界面,那么你无法真正帮助它,在这种情况下你的解决方法似乎是你能做的最好的事情。