【问题标题】:Is this C# use of CLI interface handles always guaranteed to clean up correctly?这个 C# 使用 CLI 接口句柄是否总是保证正确清理?
【发布时间】:2011-06-29 20:04:15
【问题描述】:

这是我没有按预期顺序清理的代码的简化版本。此示例代码在退出时导致访问冲突,因为正在包装的本机对象在取消订阅之前已被删除。

场景是 C# 客户端正在创建两个具体的 CLI 对象并将它们存储为接口句柄。然后设置一个具体对象来存储对另一个对象的引用,同样通过接口句柄。建立这种关系是为了提供围绕两个类的托管包装器,其中一个在本机级别订阅另一个。

我希望例如对象 A 持有对对象 B 的引用会阻止对象 B 被最终确定/处置?这不是我观察到的。有没有更好的方法来表示关系以便清理正确?

原生类:

#pragma managed(push, off)

class CNative2;

//------------------------------------------------------------------------------
class CNative1
{
public:
    CNative1(){}
    ~CNative1(){}

    void Subscribe( CNative2* pn2 )
    {
        m_pn2 = pn2;
    }

    void Unsubscribe()
    {
        m_pn2 = 0;
    }

    CNative2*   m_pn2;
};

//------------------------------------------------------------------------------
class CNative2
{
public:
    CNative2(){}
    ~CNative2()
    {
        m_pn1->Unsubscribe();
    }

    void Initialize( CNative1* pn1 )
    {
        m_pn1 = pn1;
        m_pn1->Subscribe( this );
    }

private:
    CNative1* m_pn1;
};

#pragma managed(pop)

CLI 类库代码:

#include "Native.h"

using namespace System;

namespace CLILib 
{

    //------------------------------------------------------------------------------
    public interface class Interface1
    {
    };

    //------------------------------------------------------------------------------
    public interface class Interface2
    {
        void Initialize( Interface1^ i1 );
    };

    //------------------------------------------------------------------------------
    public ref class Class1 : Interface1
    {
    public:
        Class1()
        {
            m_pn1 = new CNative1();
        };

        ~Class1()
        {
            this->!Class1();
        }

        !Class1()
        {
            delete m_pn1;
        }

    internal:
        CNative1* GetNative()
        {
            return m_pn1;
        }

    private:
        CNative1*   m_pn1;
    };

    //------------------------------------------------------------------------------
    public ref class Class2 : Interface2
    {
    public:

        Class2()
        {
            m_pn2 = new CNative2();
        }

        ~Class2()
        {
            this->!Class2();
        }

        !Class2()
        {
            delete m_pn2;
        }

        virtual void Initialize( Interface1^ i1 )
        {
            m_i1 = i1;

            Class1^ c1 = safe_cast< Class1^ >( i1 );

            m_pn2->Initialize( c1->GetNative() );
        }

        Interface1^ m_i1;

    private:
        CNative2*   m_pn2;
    };
}

C# 客户端代码:

using CLILib;

namespace ManagedClient
{
    class Program
    {
        static void Main( string[] args )
        {
            for ( int i = 0; i < 1000000; ++i )
            {
                Interface1 i1 = new Class1();
                Interface2 i2 = new Class2();
                i2.Initialize( i1 );
            }
        }
    }
}

【问题讨论】:

    标签: interface reference garbage-collection c++-cli handle


    【解决方案1】:

    好吧,我一直在努力解决这个问题,方法是从一个对象的终结器中触发一个事件,以通知另一个对象在第一个终结器完成之前清理它的本机对象。在终结器中这样做感觉有点脏。有那么糟糕吗?

    // CLILib.h
    
    #pragma once
    
    #include "Native.h"
    
    using namespace System;
    
    namespace CLILib 
    {
        interface class Interface2;
    
        //------------------------------------------------------------------------------
        public interface class Interface1
        {
        };
    
        //------------------------------------------------------------------------------
        public interface class Interface2
        {
            void Initialize( Interface1^ i1 );
        };
    
        //------------------------------------------------------------------------------
        public ref class Class1 : Interface1
        {
        public:
            Class1()
            {
                m_pn1 = new CNative1();
            };
    
            ~Class1()
            {
                this->!Class1();
            }
    
            !Class1()
            {
                OnEvent();
                delete m_pn1;
            }
    
            delegate void Eventhandler();
            event Eventhandler^ OnEvent; 
    
        internal:
            CNative1* GetNative()
            {
                return m_pn1;
            }
    
        private:
            Interface2^ m_hi2;
            CNative1*   m_pn1;
        };
    
        //------------------------------------------------------------------------------
        public ref class Class2 : Interface2
        {
        public:
    
            Class2()
            {
                m_pn2 = new CNative2();
            }
    
            ~Class2()
            {
                this->!Class2();
            }
    
            !Class2()
            {
            }
    
            virtual void Initialize( Interface1^ i1 )
            {
                m_i1 = i1;
    
               Class1^ c1 = safe_cast< Class1^ >( i1 );
    
               c1->OnEvent += gcnew Class1::Eventhandler( this, &Class2::Notify );
    
                m_pn2->Initialize( c1->GetNative() );
            }
    
            void Notify()
            {
                delete m_pn2;
                m_pn2 = nullptr;
            }
    
        private:
            Interface1^ m_i1;
            CNative2*   m_pn2;
        };
    }
    

    【讨论】:

      猜你喜欢
      • 2010-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-16
      • 2021-08-21
      • 1970-01-01
      相关资源
      最近更新 更多