Всегда ли гарантируется корректная очистка при использовании C # дескрипторов интерфейса CLI? - PullRequest
0 голосов
/ 30 июня 2011

Это упрощенная версия кода, которая у меня есть, которая не очищается в ожидаемом порядке.Этот пример кода вызывает нарушение доступа при выходе, поскольку переносимый собственный объект удаляется, прежде чем он может быть отписан от подписки.

Сценарий состоит в том, что клиент 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 );
            }
        }
    }
}

1 Ответ

0 голосов
/ 01 июля 2011

Ну, я продолжал работать над этим и решил проблему, запустив событие из финализатора одного объекта, чтобы уведомить другой о необходимости очистить свой собственный объект перед завершением первого финализатора.Это немного грязно, когда я делаю это в финализаторе.это плохо?

// 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;
    };
}
...