我应该在 C++/CLI class 中使用 C# 对象的引用还是实例?

Should I use a reference or an instance of C# objects in a C++/CLI class?

在托管 C++ class 中,我应该使用在另一个库中实现的 C# class 的引用还是实例?

考虑这个例子:

// MyManagedClass.h
#pragma once

using namespace System::Collections::Generic;
using namespace My::Namespace::MyCSharpLib;

namespace My::Namespace::MyManagedLib
{
    public ref class MyManagedClass
    {
    public:
        MyCSharpClass myInst; // i have an instance!
        MyCSharpClass ^myRef; // need to do gcnew

        List<MyCSharpClass ^> listInst; // i have an instance!
        List<MyCSharpClass ^> ^listRef; // need to do gcnew
    };
}

然后从 C# 代码调用托管 class:

// driver.cs
using My.Namespace.MyCSharpLib;
using My.Namespace.MyManagedLib;

public class Driver
{
    private static void Main(string[] args)
    {
        MyManagedClass mmc = new MyManagedClass();
        DoStuff(mmc);
    }
}

我的直觉告诉我应该使用 myReflistRef,因为如果用 C# 实现,我会这样做。但是为什么允许我直接实例化MyCSharpClass的一个实例呢?这样做的后果是什么?如果我的 class 只有一个 MyCSharpClass 对象集合,直接初始化集合是否有害?

C++/CLI 有一个名为 stack semantics 的功能,当您将引用类型成员声明为值类型 (MyCSharpClass myInst;) 时,您正在使用它。

gcnew 仍在调用,但您看不到这段代码,因为编译器会自动将它注入您的默认构造函数。请注意,它还会生成代码来处理 myInst

下面是编译器将为您的 class:

生成的 MSIL 等效的(伪)C++/CLI 代码

构造函数:

MyManagedClass()
{
    myInst = gcnew MyCSharpClass();
}

处置:

void Dispose(bool dispose)
{
    if (dispose)
    {
        try
        {
            this->~MyManagedClass();
        }
        finally
        {
            delete myInst;
        }
    }
}

编辑:

关于你关于反响的问题:使用 gcnew 手动分配意味着当你的 MyManagedClass 对象死亡时,myRef 指向的对象将仍然存在,直到垃圾收集器清理起来;而通过使用堆栈语义,您可以更确定地控制对象生命周期,而无需自己编写 Dispose 方法。

这也意味着在使用堆栈语义时,您必须小心与谁共享对象...