I'm trying to create an array of constant values that CANNOT NEVER change. I try something like this....
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 }
}
However, this array STILL gets changed from somewhere (another thread) of the code. How can I make an array constant and absolutely cannot change through the lifetime of the program? I just need to initialize this during compile time and no matter what reference or other thread change it, it should not change. But my my case, it keeps changing.
Such as, it gets changed if I do something like this later in the code, or through another thread...
HeaderKey = col.Header.ToString(),
Header = "whatever"
IsFrozen = col.IsFrozen,
IsVisible = true,
DisplayIdx = col.DisplayIndex
How do I fix it?
You don't need ImmutableArray<T>
. Just do this:
DataGrid_MarketPriceTab
from a mutable field to a getter-only property.IReadOnlyList<T>
instead of ImmutableArray<T>
because it's built-in to the .NET's BCL whereas ImmutableArray<T>
adds a dependency on System.Collections.Immutable
.Array
(ColItem[]
) but because the only reference to it is via IReadOnlyList<T>
then the collection cannot be changed without using reflection.
{ get; }
-only property means that consumers of your class cannot reassign the property value.static readonly
field.You also need to make ColItem
immutable - that can be done by making all the member-properties { get; }
instead of { get; set; }
(and ensuring their types are also immutable):
Like so:
// 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 )
};
}
If all of that seems tedious to you, I agree! The good news is that if you're using C# 9.0 or later (which requires .NET 5, unfortunately) you can use Immutable Record Types, so the class ColItem
class becomes record ColItem
:
public record ColItem(
string Header,
string HeaderKey,
bool IsFrozen = false,
bool IsVisible = true,
int DisplayIdx
);