在 C++/CLI 中将新值分配给不可变值结构

Assignment of new value to immutable value structs in C++/CLI

通常建议在 .NET 编程中使用不可变结构,因为使用可变结构容易导致简单的错误。但是,当我尝试通过实例化新结构来分配新值时,我在 C++ 中收到错误 C3892,但 C# 中的等效代码没有问题。这是一个问题,因为这会阻止我初始化不可变结构数组。

通过使用只读 属性 而不是字段可以轻松解决此问题,但我想知道为什么我不能在 C++/CLI 中执行与在 C# 中相同的操作。我做错了什么,或者这只是 C++/CLI 中的一个限制(或错误)?有什么方法可以在 C++/CLI 中使用不可变结构的数组,或者我必须避免使用它们吗?

C++ 头文件(名为 "AnnoyingCppBug.h"):

using namespace System;

namespace AnnoyingCppBug {

    public value struct immutableType
    {
        const int Value;

        immutableType(int value)
            : Value(value) {}
    };

    public value struct immutableWorkaround
    {
        property int Value
        {
            int get() { return _value; }
        }

        immutableWorkaround(int value)
            : _value(value) {}
    private:
        int _value;
    };

    public value struct mutableType
    {
        int Value;

        mutableType(int value)
            : Value(value) {}
    };

    public value struct Class1 abstract sealed
    {
        static void Test();
    };
}

C++ 源文件:

#include "stdafx.h"

#include "AnnoyingCppBug.h"

namespace AnnoyingCppBug {
    void Class1::Test()
    {
        auto imm1 = immutableType(0);
        auto imm2 = immutableWorkaround(0);
        auto imm3 = mutableType(0);

        imm1 = immutableType(1);    // error C3892: 'arr1': you cannot assign to a variable that is const
        imm2 = immutableWorkaround(1);
        imm3 = mutableType(1);

        // The reason this matters is because I need to initialize an array:
        auto arr = gcnew array<immutableType>(1);
        arr[0] = immutableType(0);  // error C3892: 'arr1': you cannot assign to a variable that is const
    }
}

执行相同但构建良好的 C# 代码:

    struct immutableType
    {
        public readonly int Value;
        public immutableType(int value)
        {
            Value = value;
        }
    }

    static void Test()
    {
        var imm = new immutableType(0);
        imm = new immutableType(1);
        var arr = new immutableType[1];
        arr[0] = new immutableType(1);
    }

我想您可能只是在创建数组时有错别字。 immutableType 后缺少 ^。这对我有用:

auto arr = gcnew array<immutableType^>(2);
arr[0] = immutableType(1);  
arr[1] = immutableType(20);  

Hans Passant 在问题的评论中提供了答案:我错误地使用了 C++ only(不是 C++/CLI)关键字 const 就好像它与 C# 关键字 readonly 的含义一样。与 C# 关键字 readonly 等效的将被编译到 CLR 中的正确关键字是 "initonly"。

const 关键字只会指示编译器生成错误,而不会生成任何不同的 CLR 字节代码。一般来说,鉴于这一启示,我建议永远不要在托管 C++ 代码中使用 const 关键字。我还认为 C++/CLI 编译器应该生成警告,但也许有充分的理由不这样做(毕竟编译器不是老师)。