首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ImmutableArray如何正确使用

ImmutableArray如何正确使用
EN

Stack Overflow用户
提问于 2021-01-11 03:55:05
回答 4查看 615关注 0票数 3

我正在尝试创建一个常量值数组,这些常量值永远不会改变。我试过这样的..。

代码语言:javascript
复制
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 }
}

但是,这个数组仍然会从代码的某个地方(另一个线程)进行更改。我如何使数组常量和绝对不能改变整个程序的生命周期?我只需要在编译期间初始化它,不管什么引用或其他线程更改它,它都不应该改变。但我的案子一直在变。

例如,如果我稍后在代码中这样做,或者通过另一个线程.

代码语言:javascript
复制
HeaderKey = col.Header.ToString(),
Header = "whatever"
IsFrozen = col.IsFrozen,
IsVisible = true,
DisplayIdx = col.DisplayIndex

我该怎么解决呢?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 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; }来实现(并确保它们的类型也是不可变的):

就像这样:

代码语言:javascript
复制
// 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

代码语言:javascript
复制
public record ColItem(
    string Header,
    string HeaderKey,
    bool   IsFrozen = false,
    bool   IsVisible = true,
    int    DisplayIdx
);
票数 2
EN

Stack Overflow用户

发布于 2021-01-11 04:24:32

使您的ColItem类不可变。这有几种方法,但最直接的方法是从属性中删除set关键字,使其成为readonly

票数 0
EN

Stack Overflow用户

发布于 2021-01-11 04:33:55

如果您想要创建一个不可变的引用类型,您可以创建所有属性的私有设置程序。或者在C# 9中,您可以只使用init属性,这些属性可以使用对象初始化器来构造。

代码语言:javascript
复制
public string Header { get; init; } 

或者,您可以更进一步,创建一个Record,它具有其他几个优点,例如:使用-表达式、基于值的相等,并且与具有继承的结构不同。

代码语言:javascript
复制
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; }
}

使用

代码语言:javascript
复制
 var test = new DatagridSettingDefault();
 test.DataGrid_MarketPriceTab[0].HeaderKey = "asd";

将生成以下编译器错误

CS8852 Init-only属性或索引器'ColItem.HeaderKey‘只能在对象初始化器中分配,或者在实例构造函数或init访问器中的'this’或'base‘上赋值。

那么剩下的就是选择一个不变的集合/集合接口。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65661142

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档