为了账号安全,请及时绑定邮箱和手机立即绑定

在 C# 中对字典进行切片

在 C# 中对字典进行切片

C#
萧十郎 2023-09-16 16:17:00
bigDict我正在尝试在 C# 中创建一个类,该类具有从 JSON 文件获取的字典 ( )。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在一些预先存在的测试用例中遇到错误(我正在重构代码)
查看完整描述

2 回答

?
慕的地8271018

TA贡献1796条经验 获得超4个赞

定义“一次性”类型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类,但任何实际通用性的尝试都会受到 C# 严格类型系统的阻碍:没有令人满意的方法来通用地告诉要对哪个属性进行切片。

可能的解决方案:

  • gettersetter作为 lambda 传递——当然您可以这样做,请注意,您的 lambda 中的代码将比实际类中的代码多。如果您需要对许多不同的属性进行切片,它可能会很有用。

  • 制作泛型类将使用的SomeStruct实现——不是非常优雅,而且如果您有许多属性需要切片,则可能非常麻烦。IGetSetElemFromStruct

  • 反射——包含在内是为了完整性,但不会对其进行扩展......

大型结构

避免大型结构;更重要的是,避免可变结构,这在 C# 中被普遍认为是非常糟糕的事情(TM) 。根据微软的设计指南,我的重点是:

一般来说,结构体非常有用,但只能用于不会经常装箱的小型、单一、不可变的值。

set {    var obj = BigDict[key];
    obj.ElemFromStruct = value;
    BigDict[key] = obj;
}

请注意,在上面的 setter 中,我获取了结构的副本,修改它,然后将其复制回字典......不太好。如果它很大,请帮自己一个忙并使用class. 然后你可以简单地写:

set { BigDict[key].ElemFromStruct = value; }

属性获取/设置中的重要操作

这是关于您作为示例编写的代码:

public virtual Dictionary<string, string> smallDict
{    get => bigDict.ToDictionary(x => x.Key, x => x.Value.ElemFromStruct);   //works fine

尽可能避开它们。没有明确的界限说明属性 getters/setters 中可以包含什么内容,但是get以任何合理的标准来看,在 a 中创建和填充字典都太过分了:想象一下,如果您不得不怀疑每个属性访问。

也许根本不使用这个

这个解决方案是我能想到的最好的解决方案,但它很笨重而且不是很有用。您必须根据您的用例自行判断,但通常直接访问/修改bigDict[key].ElemFromStruct会更好


查看完整回答
反对 回复 2023-09-16
?
拉风的咖菲猫

TA贡献1995条经验 获得超2个赞

如果我理解正确的话,您希望能够Dictionary<string, SomeStruct>从Dictionary<string, string>. 为此,您需要从字符串 Value 创建该结构的实例。这是可以完成的,但这意味着该SomeStruct值ElemFromStruct在set.


请注意,对于任何属性,在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});

    }

}

但是,如果目的只是提供一种SmallDict从 a获取 a 的方法BigDict(而不是相反),那么您可以删除该set方法,因为允许用户BigDict仅基于a 进行设置可能没有多大意义每个值对应一个字符串SomeStruct:


public virtual Dictionary<string, string> SmallDict

{

    get

    {

        return BigDict.ToDictionary(x => x.Key, x => x.Value.ElemFromStruct);

    }

}


查看完整回答
反对 回复 2023-09-16
  • 2 回答
  • 0 关注
  • 120 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信