释放临时 COM 对象
请考虑以下使用 COM 对象的 C# 代码。
MyComObject o = new MyComObject;
try
{
var baz = o.Foo.Bar.Baz;
try
{
// do something with baz
}
finally
{
Marshal.ReleaseComObject(baz);
}
}
finally
{
Marshal.ReleaseComObject(o);
}
这将释放 COM 对象 o
和 baz
,但不会释放 o.Foo
和 o.Foo.Bar 返回的临时对象
。 当这些对象持有大量非托管内存或其他资源时,这可能会导致问题。
一个明显但丑陋的解决方案是,使用 try-finally
和 Marshal.ReleaseComObject
使代码更加混乱。看 用法
作为解决方法,我创建了一个帮助程序类
class TemporaryComObjects: IDisposable
{
public C T<C>(C comObject)
{
m_objects.Add(comObject);
return comObject;
}
public void Dispose()
{
foreach (object o in m_objects)
Marshal.ReleaseComObject(o);
}
}
:
using (TemporaryComObjects t = new TemporaryComObjects())
{
MyComObject o = t.T(new MyComObject);
var baz = t.T(t.T(t.T(o.Foo).Bar).Baz);
// do something with baz
}
我的问题: 这段代码有潜在的问题吗? 有人有更优雅的解决方案吗?
Consider the following C# code using a COM object.
MyComObject o = new MyComObject;
try
{
var baz = o.Foo.Bar.Baz;
try
{
// do something with baz
}
finally
{
Marshal.ReleaseComObject(baz);
}
}
finally
{
Marshal.ReleaseComObject(o);
}
This will release the COM objects o
and baz
, but not the temporary objects returnd by o.Foo
and o.Foo.Bar
.
This can cause problems, when those objects hold a large amount of unmanaged memory or other resources.
An obvious but ugly solution would be, to clutter the code even more with try-finally
and Marshal.ReleaseComObject
. See
C# + COM Interop, deterministic release
As a workaround, I created a helper class
class TemporaryComObjects: IDisposable
{
public C T<C>(C comObject)
{
m_objects.Add(comObject);
return comObject;
}
public void Dispose()
{
foreach (object o in m_objects)
Marshal.ReleaseComObject(o);
}
}
Usage:
using (TemporaryComObjects t = new TemporaryComObjects())
{
MyComObject o = t.T(new MyComObject);
var baz = t.T(t.T(t.T(o.Foo).Bar).Baz);
// do something with baz
}
My questions:
Are there potential problems with this code?
Has anybody a more elegant solution?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我最大的抱怨是名字,
T
;Add
可能更能说明用法。我还将where T : class
添加到通用方法中,但“流畅的 API”似乎可用。我也倾向于稍微简化代码。我还可以看到一些使用Expression
API 遍历整个树并捕获所有中间步骤的方法,但这不会微不足道 - 但想象一下:在哪里是一个表达式树,我们自动获取中介。
(此外,您可以在
Dispose()
中Clear()
或null
列表)如下所示:
My biggest gripe would be the name,
T
;Add
might be more illusrative of the usage. I'd also addwhere T : class
to the generic method, but the "fluent API" seems usable. I'd also be inclined to flatten the code a bit. I can also see some ways of using theExpression
API to walk an entire tree and capture all the intermediate steps, but it wouldn't be trivial - but imagine:where that is an expression tree and we get the intermediaries automatically.
(also, you could
Clear()
ornull
the list inDispose()
)Like so: