在 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 编译器应该生成警告,但也许有充分的理由不这样做(毕竟编译器不是老师)。
通常建议在 .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 编译器应该生成警告,但也许有充分的理由不这样做(毕竟编译器不是老师)。