I'm trying to create a class in C# that has a dictionary (bigDict
) it gets from a JSON file. bigDict
maps a string to a big data structure. From this, I want to create another dictionary (smallDict
) that maps each string from the key to just one element (a string) in bigDict
's data structure value.
I've tried to use get and set to create smallDict
. I was able to successfully use get
, but I'm stuck at set
.
class myClass
{
public Dictionary<string, SomeStruct> bigDict{ get; set; } /*get and set from a JSON file*/
public virtual Dictionary<string, string> smallDict
{
get => bigDict.ToDictionary(x => x.Key, x => x.Value.ElemFromStruct); //works fine
set => smallDict.ToDictionary.update(key , value); //doesn't work fine
}
}
As a result of not being able to set properly, I'm getting property or indexer cannot be assigned to, is readonly
errors in some pre-existing test cases (I'm refactoring code)
Define a "one-off" type SmallDict
:
public SmallDict<string> smallDict;
public myClass()
{
smallDict = new SmallDict<string>(bigDict);
}
class SmallDict<TKey>
{
public readonly Dictionary<TKey, SomeStruct> BigDict;
public SmallDict(Dictionary<TKey, SomeStruct> bigDict)
{
BigDict = bigDict;
}
public string this[TKey key]
{
get => BigDict[key].ElemFromStruct;
set {
var obj = BigDict[key];
obj.ElemFromStruct = value;
BigDict[key] = obj;
}
}
}
Use it as follows:
Console.WriteLine(smallDict["key1"]); // Equivalent to printing bigDict[key].ElemFromStruct
smallDict["key1"] = "new value"; // Equivalent to bigDict[key].ElemFromStruct = "new value"
It's a mere wrapper around a dictionary, so if you want more methods than plain indexing, you'll have to do all the plumbing manually.
Notice how SmallDict
only works for dictionaries of SomeStruct
...
I would have written a generic DictionarySlice class, but any attempt at actual genericity is thwarted by C#'s rigid type system: there is no sastisfying way to genericly tell which property to slice on.
Possible solutions:
SomeStruct
implement IGetSetElemFromStruct
which the generic class would use -- not terribly elegant and potentially extremely cumbersome if you have many properties to slice on.Avoid large structs; and more importantly avoid mutable structs, which are universally considered a Very Bad Thing(TM) in C#. From Microsoft's design guidelines, emphasis mine:
In general, structs can be very useful but should only be used for small, single, immutable values that will not be boxed frequently.
set {
var obj = BigDict[key];
obj.ElemFromStruct = value;
BigDict[key] = obj;
}
Notice that in the setter above, I get a copy of the struct, modify it, and copy it back to the dictionary... not great. If it's gonna be large, do yourself a favor and use a class
. You would then simply write:
set { BigDict[key].ElemFromStruct = value; }
This is about the code you wrote as an example:
public virtual Dictionary<string, string> smallDict
{
get => bigDict.ToDictionary(x => x.Key, x => x.Value.ElemFromStruct); //works fine
Avoid them as much as possible. There is no definite line saying what can go in properties getters/setters, but creating and populating a dictionary in a get
is simply way too much by any reasonable standard: imagine if you had to doubt every property access.
This solution is the best I could come up with, but it's clunky and not terribly useful. You have to judge for yourself depending on your use-case, but generally accessing/mutating bigDict[key].ElemFromStruct
directly would be better.