存储对构造函数初始值设定项中创建的对象的引用
摘要:如果我在构造函数初始化程序中创建一个对象,如何保留对其的引用以便以后可以引用它?
详细信息:
我有一个类(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
实例的引用,以便我稍后可以处理它。
我的问题:
- 我在这里缺少什么?我觉得我正在与语言作斗争。 C# 是否提供了更好的方法来做到这一点?
- 如果该语言不直接支持这一点,是否有比我的私有构造函数技术更好的解决方案?
- 对我的解决方案中的缺陷有何评论?
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:
- What am I missing here? I feel like I'm fighting the language. Does C# provide a better way to do this?
- If the language doesn't directly support this, is there a better solution than my private constructor technique?
- Any comments on defects in my solution?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我不认为你在这里遗漏了任何东西。如果
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:
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.)
你的解决方案看起来不错...我不认为你错过了任何东西...
如果你想改变实现(无论出于何种原因):
但是正如我所说,您的解决方案没有任何问题(如果经常发生,您可能应该重新考虑你的设计)。
编辑 - 根据评论:
我所说的“创建 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):
LibBase
but having an instance as a private member...MyClass
thus having no public constructor and creating theStreamWriter
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 theStreamWriter
instance in the Factory method and pass it in as param toMyClass
... this way you could even implement some fancy things like "whichMyClass
instance is using a givenStreamWriter
instance ?" or some sort of a cache forMyClass
/StreamWriter
instances etc.我认为在这种情况下,您不应该派生 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 useLibBase
does not, so you can't simply throw instance ofMyClass
at code written to handleLibBase
. In such cases inheritance is not really appropriate. Of course ifLibBase
doubles as an interface, you can't really help it in which case your workaround seems like the best thing you can do.