存储对构造函数初始值设定项中创建的对象的引用

发布于 2024-12-08 14:43:22 字数 1538 浏览 0 评论 0原文

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

详细信息

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

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

我从 LibBase 派生了 MyClass ,并且在 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. 对我的解决方案中的缺陷有何评论?

Summary: if I create an object in a constructor initialiser, how do I keep a reference to it so I can reference it later?

Details:

I have a class (LibBase, below) that requires a StreamWriter as its construction parameter. I don't have the source code for LibBase - its in a third-party library.

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

I have derived MyClass from LibBase and in the MyClass constructor I want to pass an instance of MyWriter (derived form StreamWriter) to the base class. I do this as follows.

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))
    { }
}

The problem is that MyWriter requires disposing, so MyClass should dispose it (and implement IDisposable to do this) but MyClass doesn't have a reference to the created MyWriter instance, so I can't dispose it. The syntax for the constructor initialiser doesn't seem to permit my to keep a reference.

My solution is to re-code MyClass as follows:

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
}

The private constructor stores a reference to the MyWriter instance so I can dispose it later.

My questions:

  1. What am I missing here? I feel like I'm fighting the language. Does C# provide a better way to do this?
  2. If the language doesn't directly support this, is there a better solution than my private constructor technique?
  3. Any comments on defects in my solution?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

诗笺 2024-12-15 14:43:22

我不认为你在这里遗漏了任何东西。如果 LibBase 确实不允许您获取传递给构造函数的编写器,那么您的解决方案对我来说看起来不错。

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

频道 Eric Lippert

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

我猜这是不符合标准的东西,即使它一开始就被认为是可取的。 (除了 C# 团队的成本之外,还有持续的成本 - C# 开发人员吸收每个功能的心理成本,以及每个新功能的持续成本可能会导致添加下一个功能变得更加困难。 )

I don't think you're missing anything here. Your solution looks okay to me if LibBase really doesn't let you get at the writer you passed in to the constructor.

I suspect that the reason there isn't more explicit support for this is that it doesn't crop up very often. If you find it cropping up very often in your designs, it's possible that you're overusing inheritance.

To channel Eric Lippert:

However, as I often point out, I don't have to provide a justification for not doing a feature. Features aren't cheap; they are extremely expensive and they must not only justify their own cost, they must justify the opportunity cost of not doing the hundred other features we could have done with that budget. We must justify the cost of features to our stakeholders, but we need not justify saving time and effort by not implementing features that don't meet our bar.

My guess this is something which doesn't meet the bar, even if it were deemed desirable in the first place. (There's ongoing cost beyond the cost to the C# team - there's the mental cost of each feature being absorbed by C# developers, and the ongoing cost that each new feature makes it potentially harder to add the next feature.)

酒儿 2024-12-15 14:43:22

你的解决方案看起来不错...我不认为你错过了任何东西...

如果你想改变实现(无论出于何种原因):

  • 你可以通过不继承 LibBase 而是拥有来实现它作为私有成员的实例...
  • 另一个选择是为 MyClass 实现工厂模式,从而没有公共构造函数并在工厂端创建 StreamWriter 实例等。

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

编辑 - 根据评论:

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

Your solution seems ok... I don't think that you miss anything...

IF you want to change the implementation (for whatever reason):

  • You could implement that by not inheriting from LibBase but having an instance as a private member...
  • another option would be to implement the Factory pattern for MyClass thus having no public constructor and creating the StreamWriter instance factory-side etc.

BUT as I said there is nothing wrong with you solution (if it happens often you probably should rethink your design).

EDIT - as per comment:

What I mean by "creating StreamWriter factory-side" is: create a Factory for MyClass so that anyone needing an instance uses the Factory... therein you can create the StreamWriter instance in the Factory method and pass it in as param to MyClass... this way you could even implement some fancy things like "which MyClass instance is using a given StreamWriter instance ?" or some sort of a cache for MyClass / StreamWriter instances etc.

抽个烟儿 2024-12-15 14:43:22

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

任何处理 MyClass 的人都必须处理处置,但使用 LibBase 编写的代码则不需要,因此您不能简单地抛出 MyClass 的实例为处理LibBase而编写的代码。在这种情况下,继承并不是真正合适的。当然,如果 LibBase 兼作接口,您将无能为力,在这种情况下,您的解决方法似乎是您能做的最好的事情。

I think that in this case you shouldn't be deriving LibBase but delegating to it. In which case you can obviously initialize the members in any order you want.

Anybody dealing with MyClass has to handle the disposal, but code written to use LibBase does not, so you can't simply throw instance of MyClass at code written to handle LibBase. In such cases inheritance is not really appropriate. Of course if LibBase doubles as an interface, you can't really help it in which case your workaround seems like the best thing you can do.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文