我正在尝试创建一个常量值数组,这些常量值永远不会改变。我试过这样的..。
public class ColItem
{
public string Header { get; set; } // real header name in ENG/CHI
public string HeaderKey { get; set; } // header identifier
public bool IsFrozen { get; set; } = false;
public bool IsVisible { get; set; } = true;
public int DisplayIdx { get; set; }
}
public struct DatagridSettingDefault
{
public static ImmutableArray<ColItem> DataGrid_MarketPriceTab = ImmutableArray.Create(new ColItem[] {
new ColItem { HeaderKey = "ORDER_ID", IsFrozen = true, DisplayIdx = 0 },
new ColItem { HeaderKey = "PRICE_RENAMEPROMPT", IsFrozen = false, DisplayIdx = 1 },
new ColItem { HeaderKey = "PRICETBL_TRADESTATENO", IsFrozen = false, DisplayIdx = 2 },
new ColItem { HeaderKey = "PRICETBL_BIDQTY", DisplayIdx = 3 },
new ColItem { HeaderKey = "PRICETBL_BID", DisplayIdx = 4 },
new ColItem { HeaderKey = "PRICETBL_ASK", DisplayIdx = 5 },
new ColItem { HeaderKey = "PRICETBL_ASKQTY", DisplayIdx = 6 }
}但是,这个数组仍然会从代码的某个地方(另一个线程)进行更改。我如何使数组常量和绝对不能改变整个程序的生命周期?我只需要在编译期间初始化它,不管什么引用或其他线程更改它,它都不应该改变。但我的案子一直在变。
例如,如果我稍后在代码中这样做,或者通过另一个线程.
HeaderKey = col.Header.ToString(),
Header = "whatever"
IsFrozen = col.IsFrozen,
IsVisible = true,
DisplayIdx = col.DisplayIndex我该怎么解决呢?
发布于 2021-01-11 04:21:31
你不需要ImmutableArray<T>。就这么做吧:
DataGrid_MarketPriceTab从可变字段更改为纯getter属性。IReadOnlyList<T>而不是ImmutableArray<T>,因为它内置于.NET的BCL,而ImmutableArray<T>则增加了对System.Collections.Immutable的依赖。Array (ColItem[])的,但是由于对它的唯一引用是通过IReadOnlyList<T>,所以如果不使用反射,就不能更改集合。{ get; }-only属性意味着类的使用者不能重新分配属性值。static readonly字段。您还需要使ColItem不可变-这可以通过使所有成员属性{ get; }而不是{ get; set; }来实现(并确保它们的类型也是不可变的):
就像这样:
// This is an immutable type: properties can only be set in the constructor.
public class ColItem
{
public ColItem(
string headerName, string headerKey, int displayIdx,
bool isFrozen = false, bool isVisible = true
)
{
this.Header = headerName ?? throw new ArgumentNullException(nameof(headerName));
this.HeaderKey = headerKey ?? throw new ArgumentNullException(nameof(headerKey));
this.IsFrozen = isFrozen;
this.IsVisible = isVisible;
this.DisplayIdx = displayIdx;
}
public string Header { get; }
public string HeaderKey { get; }
public bool IsFrozen { get; }
public bool IsVisible { get; }
public int DisplayIdx { get; }
}
public struct DatagridSettingDefault // Why is this a struct and not a static class?
{
public static IReadOnlyList<ColItem> DataGrid_MarketPriceTab { get; } = new[]
{
new ColItem( headerName: "Order Id", headerKey: "ORDER_ID", isFrozen: true, displayIdx: 0 ),
new ColItem( headerName: "Price", headerKey: "PRICE_RENAMEPROMPT", IsFrozen:false, displayIdx:1 ),
new ColItem( headerName: "Foo", headerKey: "PRICETBL_TRADESTATENO", IsFrozen:false, displayIdx:2 ),
new ColItem( headerName: "Bar", headerKey: "PRICETBL_BIDQTY", displayIdx:3 ),
new ColItem( headerName: "Baz", headerKey: "PRICETBL_BID", displayIdx:4 ),
new ColItem( headerName: "Qux", headerKey: "PRICETBL_ASK", displayIdx:5 ),
new ColItem( headerName: "Hmmm", headerKey: "PRICETBL_ASKQTY", displayIdx:6 )
};
}如果这一切对你来说都很乏味的话,我同意!好消息是如果您使用的是C# 9.0或更高版本(不幸的是,这需要.NET 5 ),您可以使用不可变的记录类型,所以class ColItem类变成了record ColItem
public record ColItem(
string Header,
string HeaderKey,
bool IsFrozen = false,
bool IsVisible = true,
int DisplayIdx
);发布于 2021-01-11 04:24:32
使您的ColItem类不可变。这有几种方法,但最直接的方法是从属性中删除set关键字,使其成为readonly。
发布于 2021-01-11 04:33:55
如果您想要创建一个不可变的引用类型,您可以创建所有属性的私有设置程序。或者在C# 9中,您可以只使用init属性,这些属性可以使用对象初始化器来构造。
public string Header { get; init; } 或者,您可以更进一步,创建一个Record,它具有其他几个优点,例如:使用-表达式、基于值的相等,并且与具有继承的结构不同。
public record ColItem
{
public string Header { get; init; } // real header name in ENG/CHI
public string HeaderKey { get; init; } // header identifier
public bool IsFrozen { get; init; } = false;
public bool IsVisible { get; init; } = true;
public int DisplayIdx { get; init; }
}使用
var test = new DatagridSettingDefault();
test.DataGrid_MarketPriceTab[0].HeaderKey = "asd";将生成以下编译器错误
CS8852 Init-only属性或索引器'ColItem.HeaderKey‘只能在对象初始化器中分配,或者在实例构造函数或init访问器中的'this’或'base‘上赋值。
那么剩下的就是选择一个不变的集合/集合接口。
https://stackoverflow.com/questions/65661142
复制相似问题