C # + COM Interop, детерминированный релиз

COM-объекты обычно имеют детерминированное разрушение: они освобождаются при освобождении последней ссылки.

Как это обрабатывается в C # - COM Interop? Классы не реализуют IDisposable, поэтому я не вижу способа вызвать явный IUnknown :: Release.

Случайный тест показывает, что несвязанные COM-объекты собираются лениво (то есть сборщик мусора запускает выпуск). Что я должен сделать для объектов OCM, которые должны быть освобождены агрессивно? (например, хранение крупных или общих критических ресурсов)?

Исходная проблема: у нас есть приложение C #, интенсивно использующее библиотеку COM, и оно протекает как сумасшедший. Кажется, что проблема заключается «между» кодом C ++ и C # (у нас есть доступ к обоим), но мы не можем его пригвоздить.

12 голосов | спросил peterchen 4 J0000006Europe/Moscow 2009, 12:06:24

2 ответа


0

Вы можете управлять ссылками COM-взаимодействия с помощью класса System.Runtime.InteropServices.Marshal. В частности, вы можете захотеть взглянуть на маршала. ReleaseComObject .

ответил Jakob Christensen 4 J0000006Europe/Moscow 2009, 12:12:07
0

Это из связанного (но слегка отличающегося) вопроса , но я думаю, что ответ довольно аккуратный - так что я подумал здесь тоже стоит добавить.

Вот вариант, который использует деревья Expression для обсуждения наших намерений, захвата значения на каждом узле - допуская один выпуск:

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 WalkImpl(Expression expr)
    {
        switch (expr.NodeType)
        {
            case ExpressionType.Constant:
                return ((ConstantExpression)expr).Value;
            case ExpressionType.New:
                NewExpression ne = (NewExpression)expr;
                object[] args = ne.Arguments.Select(arg => Walk(arg)).ToArray();
                return ne.Constructor.Invoke(args);
            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();

                }
            default:
                throw new NotSupportedException();
        }
    }
    public void Dispose()
    {
        foreach(object obj in objects) {
            Marshal.ReleaseComObject(obj);
            Debug.WriteLine("Released: " + obj);
        }
        objects.Clear();
    }
}
ответил Marc Gravell 3 FebruaryEurope/MoscowbWed, 03 Feb 2010 15:05:54 +0300000000pmWed, 03 Feb 2010 15:05:54 +030010 2010, 15:05:54

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132