使用COM对象考虑下面的C#code。
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);
}
这将释放COM对象 0
和巴兹
,而不是由returnd临时对象 o.Foo
和 o.Foo.Bar
。
这可能导致问题,当这些对象持有大量的非托管存储器或其他资源。
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.
这是显而易见的,但丑陋的解决办法是,以更加与杂乱code尝试,终于
和 Marshal.ReleaseComObject的
。看到
C#+ COM互操作的,确定性的释放
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);
}
}
用法:
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
}
我的提问: 是否有与此code潜在的问题? 有没有人一个更好的解决方案?
My questions: Are there potential problems with this code? Has anybody a more elegant solution?
推荐答案
我最大的抱怨是名称, T
; 添加
可能是使用了更illusrative。我还添加其中T:类
的泛型方法,但一口流利的API似乎可用。我还倾向于扁平化℃的位$ C $。我还可以看到使用防爆pression
API走整个目录树和捕获所有的中间步骤的一些方法,但它不会是的小事的 - 但是想象一下:
My biggest gripe would be the name, T
; Add
might be more illusrative of the usage. I'd also add where 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 the Expression
API to walk an entire tree and capture all the intermediate steps, but it wouldn't be trivial - but imagine:
using(var com = new SomeWrapper()) {
var baz = com.Add(() => new MyComObject().Foo.Bar.Baz);
}
其中,这是一个前pression树,我们会自动获得中介。
where that is an expression tree and we get the intermediaries automatically.
(也可以清除()
或空
的列表中处置( )
)
像这样:
static class ComExample {
static void Main()
{
using (var wrapper = new ReleaseWrapper())
{
var baz = wrapper.Add(
() => new Foo().Bar.Baz);
Console.WriteLine(baz.Name);
}
}
}
class ReleaseWrapper : IDisposable
{
List<object> objects = new List<object>();
public T Add<T>(Expression<Func<T>> func)
{
return (T)Walk(func.Body);
}
object Walk(Expression expr)
{
object obj = WalkImpl(expr);
if (obj != null && Marshal.IsComObject(obj) && !objects.Contains(obj))
{
objects.Add(obj);
}
return obj;
}
object[] Walk(IEnumerable<Expression> args)
{
if (args == null) return null;
return args.Select(arg => Walk(arg)).ToArray();
}
object WalkImpl(Expression expr)
{
switch (expr.NodeType)
{
case ExpressionType.Constant:
return ((ConstantExpression)expr).Value;
case ExpressionType.New:
NewExpression ne = (NewExpression)expr;
return ne.Constructor.Invoke(Walk(ne.Arguments));
case ExpressionType.MemberAccess:
MemberExpression me = (MemberExpression)expr;
object target = Walk(me.Expression);
switch (me.Member.MemberType)
{
case MemberTypes.Field:
return ((FieldInfo)me.Member).GetValue(target);
case MemberTypes.Property:
return ((PropertyInfo)me.Member).GetValue(target, null);
default:
throw new NotSupportedException();
}
case ExpressionType.Call:
MethodCallExpression mce = (MethodCallExpression)expr;
return mce.Method.Invoke(Walk(mce.Object), Walk(mce.Arguments));
default:
throw new NotSupportedException();
}
}
public void Dispose()
{
foreach(object obj in objects) {
Marshal.ReleaseComObject(obj);
Debug.WriteLine("Released: " + obj);
}
objects.Clear();
}
}
相关推荐
最新文章