在 C# 中对字典进行切片
Slicing a Dictionary in C#
我正在尝试在 C# 中创建一个 class,它具有从 JSON 文件获取的字典 (bigDict
)。 bigDict
将字符串映射到大数据结构。由此,我想创建另一个字典 (smallDict
),它将键中的每个字符串映射到 bigDict
的数据结构值中的一个元素(字符串)。
我试过使用 get 和 set 来创建 smallDict
。我能够成功使用 get
,但我卡在了 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
}
}
由于无法正确设置,我在一些预先存在的测试用例中遇到 property or indexer cannot be assigned to, is readonly
错误(我正在重构代码)
如果我没理解错的话,您希望能够从 Dictionary<string, string>
创建 Dictionary<string, SomeStruct>
。为此,您需要从字符串值创建结构的实例。可以做到,但这意味着 SomeStruct
值将仅在 set
.
期间分配单个 属性 (ElemFromStruct
)
请注意,对于任何 属性,在 set
方法内部,有一个可用的 value
变量,它与 属性 的类型相同(Dictionary<string, string>
在这种情况下),它表示正在传递到 set
方法的项目。这在下面用作 value.ToDictionary(...
例如:
public virtual Dictionary<string, string> SmallDict
{
get
{
return BigDict.ToDictionary(x => x.Key, x => x.Value.ElemFromStruct);
}
set
{
BigDict = value.ToDictionary(x => x.Key,
x => new SomeStruct {ElemFromStruct = x.Value});
}
}
但是,如果目的只是提供一种从 BigDict
获取 SmallDict
的方法(而不是反过来),那么您只需删除 set
方法,因为允许用户仅基于单个字符串为每个 SomeStruct
值设置 BigDict
可能没有多大意义:
public virtual Dictionary<string, string> SmallDict
{
get
{
return BigDict.ToDictionary(x => x.Key, x => x.Value.ElemFromStruct);
}
}
定义一个"one-off"类型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;
}
}
}
使用方法如下:
Console.WriteLine(smallDict["key1"]); // Equivalent to printing bigDict[key].ElemFromStruct
smallDict["key1"] = "new value"; // Equivalent to bigDict[key].ElemFromStruct = "new value"
它只是字典的包装器,因此如果您需要比普通索引更多的方法,则必须手动完成所有管道。
通用性
请注意 SmallDict
如何仅适用于 SomeStruct
...
的词典
我会写一个通用的 DictionarySlice class,但是任何实际通用性的尝试都会被 C# 严格的类型系统所挫败:没有令人满意的方式来通用地告诉属性 切片。
可能的解决方案:
- 将 getters 和 setters 作为 lambda 传递——当然你可以这样做,你会有更多的代码请注意,您的 lambda 表达式比实际 class 中的要大。如果您需要对许多不同的属性进行切片,它可能会很有用。
- 使
SomeStruct
实现通用 class 将使用的 IGetSetElemFromStruct
-- 不是非常优雅,如果您有许多属性要分割的话,可能会非常麻烦。
- 反思 -- 为了完整性而包括在内,但不会对其进行扩展...
大型结构
避免大结构;更重要的是 避免可变结构 ,它被普遍认为是 Very Bad Thing(TM) in C#. From Microsoft's design guidelines,强调我的:
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;
}
请注意,在上面的 setter 中,我获取了结构的副本,对其进行修改,然后将其复制回字典中……不太好。如果它会很大,帮自己一个忙 使用 class
。然后你只需写:
set { BigDict[key].ElemFromStruct = value; }
属性中的重要操作 get/set
这是关于您作为示例编写的代码:
public virtual Dictionary<string, string> smallDict
{
get => bigDict.ToDictionary(x => x.Key, x => x.Value.ElemFromStruct); //works fine
尽可能避开它们。没有明确说明属性 getters/setters 中可以包含哪些内容,但是在 get
中创建和填充字典以任何合理的标准来说都太过分了:想象一下,如果您不得不怀疑 每个 属性 访问。
也许根本不用这个
这个解决方案是我能想到的最好的解决方案,但它很笨重而且不是很有用。你必须根据你的用例自己判断,但通常 accessing/mutating bigDict[key].ElemFromStruct
直接 .
会更好
我正在尝试在 C# 中创建一个 class,它具有从 JSON 文件获取的字典 (bigDict
)。 bigDict
将字符串映射到大数据结构。由此,我想创建另一个字典 (smallDict
),它将键中的每个字符串映射到 bigDict
的数据结构值中的一个元素(字符串)。
我试过使用 get 和 set 来创建 smallDict
。我能够成功使用 get
,但我卡在了 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
}
}
由于无法正确设置,我在一些预先存在的测试用例中遇到 property or indexer cannot be assigned to, is readonly
错误(我正在重构代码)
如果我没理解错的话,您希望能够从 Dictionary<string, string>
创建 Dictionary<string, SomeStruct>
。为此,您需要从字符串值创建结构的实例。可以做到,但这意味着 SomeStruct
值将仅在 set
.
ElemFromStruct
)
请注意,对于任何 属性,在 set
方法内部,有一个可用的 value
变量,它与 属性 的类型相同(Dictionary<string, string>
在这种情况下),它表示正在传递到 set
方法的项目。这在下面用作 value.ToDictionary(...
例如:
public virtual Dictionary<string, string> SmallDict
{
get
{
return BigDict.ToDictionary(x => x.Key, x => x.Value.ElemFromStruct);
}
set
{
BigDict = value.ToDictionary(x => x.Key,
x => new SomeStruct {ElemFromStruct = x.Value});
}
}
但是,如果目的只是提供一种从 BigDict
获取 SmallDict
的方法(而不是反过来),那么您只需删除 set
方法,因为允许用户仅基于单个字符串为每个 SomeStruct
值设置 BigDict
可能没有多大意义:
public virtual Dictionary<string, string> SmallDict
{
get
{
return BigDict.ToDictionary(x => x.Key, x => x.Value.ElemFromStruct);
}
}
定义一个"one-off"类型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;
}
}
}
使用方法如下:
Console.WriteLine(smallDict["key1"]); // Equivalent to printing bigDict[key].ElemFromStruct
smallDict["key1"] = "new value"; // Equivalent to bigDict[key].ElemFromStruct = "new value"
它只是字典的包装器,因此如果您需要比普通索引更多的方法,则必须手动完成所有管道。
通用性
请注意 SmallDict
如何仅适用于 SomeStruct
...
我会写一个通用的 DictionarySlice class,但是任何实际通用性的尝试都会被 C# 严格的类型系统所挫败:没有令人满意的方式来通用地告诉属性 切片。
可能的解决方案:
- 将 getters 和 setters 作为 lambda 传递——当然你可以这样做,你会有更多的代码请注意,您的 lambda 表达式比实际 class 中的要大。如果您需要对许多不同的属性进行切片,它可能会很有用。
- 使
SomeStruct
实现通用 class 将使用的IGetSetElemFromStruct
-- 不是非常优雅,如果您有许多属性要分割的话,可能会非常麻烦。 - 反思 -- 为了完整性而包括在内,但不会对其进行扩展...
大型结构
避免大结构;更重要的是 避免可变结构 ,它被普遍认为是 Very Bad Thing(TM) in C#. From Microsoft's design guidelines,强调我的:
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;
}
请注意,在上面的 setter 中,我获取了结构的副本,对其进行修改,然后将其复制回字典中……不太好。如果它会很大,帮自己一个忙 使用 class
。然后你只需写:
set { BigDict[key].ElemFromStruct = value; }
属性中的重要操作 get/set
这是关于您作为示例编写的代码:
public virtual Dictionary<string, string> smallDict
{
get => bigDict.ToDictionary(x => x.Key, x => x.Value.ElemFromStruct); //works fine
尽可能避开它们。没有明确说明属性 getters/setters 中可以包含哪些内容,但是在 get
中创建和填充字典以任何合理的标准来说都太过分了:想象一下,如果您不得不怀疑 每个 属性 访问。
也许根本不用这个
这个解决方案是我能想到的最好的解决方案,但它很笨重而且不是很有用。你必须根据你的用例自己判断,但通常 accessing/mutating bigDict[key].ElemFromStruct
直接 .