<i id='gJJvc'><tr id='gJJvc'><dt id='gJJvc'><q id='gJJvc'><span id='gJJvc'><b id='gJJvc'><form id='gJJvc'><ins id='gJJvc'></ins><ul id='gJJvc'></ul><sub id='gJJvc'></sub></form><legend id='gJJvc'></legend><bdo id='gJJvc'><pre id='gJJvc'><center id='gJJvc'></center></pre></bdo></b><th id='gJJvc'></th></span></q></dt></tr></i><div id='gJJvc'><tfoot id='gJJvc'></tfoot><dl id='gJJvc'><fieldset id='gJJvc'></fieldset></dl></div>
<tfoot id='gJJvc'></tfoot>

    <bdo id='gJJvc'></bdo><ul id='gJJvc'></ul>
  • <small id='gJJvc'></small><noframes id='gJJvc'>

      <legend id='gJJvc'><style id='gJJvc'><dir id='gJJvc'><q id='gJJvc'></q></dir></style></legend>

      1. 释放临时 COM 对象

        时间:2023-07-26
          <bdo id='YXMIt'></bdo><ul id='YXMIt'></ul>
          <i id='YXMIt'><tr id='YXMIt'><dt id='YXMIt'><q id='YXMIt'><span id='YXMIt'><b id='YXMIt'><form id='YXMIt'><ins id='YXMIt'></ins><ul id='YXMIt'></ul><sub id='YXMIt'></sub></form><legend id='YXMIt'></legend><bdo id='YXMIt'><pre id='YXMIt'><center id='YXMIt'></center></pre></bdo></b><th id='YXMIt'></th></span></q></dt></tr></i><div id='YXMIt'><tfoot id='YXMIt'></tfoot><dl id='YXMIt'><fieldset id='YXMIt'></fieldset></dl></div>
          • <legend id='YXMIt'><style id='YXMIt'><dir id='YXMIt'><q id='YXMIt'></q></dir></style></legend>

            <small id='YXMIt'></small><noframes id='YXMIt'>

                    <tbody id='YXMIt'></tbody>

                  <tfoot id='YXMIt'></tfoot>
                  本文介绍了释放临时 COM 对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

                  问题描述

                  考虑以下使用 COM 对象的 C# 代码.

                  <上一页><代码>MyComObject o = 新的 MyComObject;尝试{var baz = o.Foo.Bar.Baz;尝试{//用 baz 做一些事情}最后{Marshal.ReleaseComObject(baz);}}最后{Marshal.ReleaseComObject(o);}

                  这将释放 COM 对象 obaz,但不会释放 o.Fooo 返回的临时对象.Foo.Bar.当这些对象拥有大量非托管内存或其他资源时,这可能会导致问题.

                  一个明显但丑陋的解决方案是,使用 try-finallyMarshal.ReleaseComObject 使代码更加混乱.看C# + COM 互操作,确定性发布

                  作为一种解决方法,我创建了一个辅助类

                  <上一页><代码>类 TemporaryComObjects:IDisposable{公共 C T<C>(C comObject){m_objects.Add(comObject);返回comObject;}公共无效处置(){foreach(m_objects 中的对象 o)Marshal.ReleaseComObject(o);}}

                  用法:

                  <上一页><代码>使用 (TemporaryComObjects t = new TemporaryComObjects()){MyComObject o = t.T(new MyComObject);var baz = t.T(t.T(t.T(o.Foo).Bar).Baz);//用 baz 做一些事情}

                  我的问题:此代码是否存在潜在问题?有没有更优雅的解决方案?

                  解决方案

                  我最大的抱怨是名字,T;Add 可能更能说明用法.我还将 where T : class 添加到通用方法中,但流利的 API"似乎可用.我也倾向于稍微扁平化代码.我还可以看到一些使用 Expression API 遍历整个树并捕获所有中间步骤的方法,但它不会是微不足道的 - 但想象一下:

                  使用(var com = new SomeWrapper()) {var baz = com.Add(() => new MyComObject().Foo.Bar.Baz);}

                  这是一个表达式树,我们会自动获取中介.

                  (另外,您可以 Clear()null Dispose() 中的列表)

                  <小时>

                  像这样:

                  静态类 ComExample {静态无效主要(){使用 (var wrapper = new ReleaseWrapper()){var baz = wrapper.Add(() =>新的 Foo().Bar.Baz);Console.WriteLine(baz.Name);}}}类 ReleaseWrapper : IDisposable{列表<对象>对象=新列表<对象>();public T Add<T>(表达式<Func<T>> func){返回 (T)Walk(func.Body);}对象行走(表达式 expr){对象 obj = WalkImpl(expr);if (obj != null && Marshal.IsComObject(obj) && !objects.Contains(obj)){objects.Add(obj);}返回对象;}object[] Walk(IEnumerable<表达式> args){如果(args == null)返回null;return args.Select(arg => Walk(arg)).ToArray();}对象 WalkImpl(表达式 expr){开关(expr.NodeType){案例ExpressionType.Constant:返回 ((ConstantExpression)expr).Value;案例ExpressionType.New:新表达式 ne = (NewExpression)expr;返回 ne.Constructor.Invoke(Walk(ne.Arguments));案例ExpressionType.MemberAccess:MemberExpression me = (MemberExpression)expr;对象目标 = 步行(me.Expression);开关(me.Member.MemberType){案例成员类型.字段:return ((FieldInfo)me.Member).GetValue(target);案例 MemberTypes.Property:return ((PropertyInfo)me.Member).GetValue(target, null);默认:抛出新的 NotSupportedException();}案例ExpressionType.Call:MethodCallExpression mce = (MethodCallExpression)expr;返回 mce.Method.Invoke(Walk(mce.Object), Walk(mce.Arguments));默认:抛出新的 NotSupportedException();}}公共无效处置(){foreach(对象中的对象 obj){Marshal.ReleaseComObject(obj);Debug.WriteLine("已发布:" + obj);}对象.清除();}}

                  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?

                  解决方案

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

                  where that is an expression tree and we get the intermediaries automatically.

                  (also, you could Clear() or null the list in Dispose())


                  Like so:

                  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();
                      }
                  }
                  

                  这篇关于释放临时 COM 对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

                  上一篇:向 COM 公开 .NET 事件? 下一篇:在托管 STA 应用程序中处理来自进程外 COM 服务器的事件

                  相关文章

                  1. <i id='cN0Ok'><tr id='cN0Ok'><dt id='cN0Ok'><q id='cN0Ok'><span id='cN0Ok'><b id='cN0Ok'><form id='cN0Ok'><ins id='cN0Ok'></ins><ul id='cN0Ok'></ul><sub id='cN0Ok'></sub></form><legend id='cN0Ok'></legend><bdo id='cN0Ok'><pre id='cN0Ok'><center id='cN0Ok'></center></pre></bdo></b><th id='cN0Ok'></th></span></q></dt></tr></i><div id='cN0Ok'><tfoot id='cN0Ok'></tfoot><dl id='cN0Ok'><fieldset id='cN0Ok'></fieldset></dl></div>
                    <legend id='cN0Ok'><style id='cN0Ok'><dir id='cN0Ok'><q id='cN0Ok'></q></dir></style></legend>
                  2. <small id='cN0Ok'></small><noframes id='cN0Ok'>

                      • <bdo id='cN0Ok'></bdo><ul id='cN0Ok'></ul>

                    1. <tfoot id='cN0Ok'></tfoot>