使用Dictionary<string, object>作为Dictionary<string, Dictionary<string, string>>

3
在C#中,我需要将数据保存在字典对象中,看起来像这样:
Dictionary<string, Dictionary<string, string>> MyDict = 
    new Dictionary<string, Dictionary<string, string>>();

现在我意识到,在某些情况下,我需要一些其他(不是类似于字典的)数据作为主要字典的值。

如果我将主字典实例化为以下方式,是否存在任何问题或限制:

Dictionary<string, object> MyDict = new Dictionary<string, object>();

在对象字段中,我可以放置字符串、字典或任何其他内容。
提前感谢您的帮助, 最好的问候,Steven

标题与您的问题内容不符 - vulkanino
我认为这不应该是一个问题。当访问它时,你可能只需要将其转换为它应该是的类型。 - Kevin
你可以在https://dev59.com/ynRB5IYBdhLWcg3wn4bb找到答案,这是你想要的吗? - DotNetUser
这是一个非常奇怪的要求。我的第一个建议是重新考虑设计,真的。问题中没有太多信息可以建议一个解决方案。否则,我猜你可以维护两个单独的字典。如果不行,可以看看Oliver的面向对象的解决方案。迄今为止,这是最好的解决方案。 - nawfal
7个回答

5

是的,您的词典将不再是强类型的 - 在第一种方法中,您可以做类似以下操作:

string value = myDict["foo"]["bar"];

在第二种方法中,这不再是可能的,因为您必须先进行强制转换:
string value = ((Dictionary<string,string>)myDict["foo"])["bar"];

听起来你的问题可能可以通过更好的设计方法来解决。通常,通过重新设计解决方案,可以避免需要在同一数据结构中存储不同类型的对象 - 那么你为什么需要这样做呢?

编辑:

如果你只想处理null值,你可以做如下操作:

string value = myDict["foo"] != null ? myDict["foo"]["bar"] : null;

或者使用扩展方法进行包装:

public static T GetValue<T>(this Dictionary<T, Dictionary<T,T>> dict, 
                            T key, T subKey) where T: class
{
    T value = dict[key] != null ? dict[key][subKey] : null;
    return value;
}

string value = myDict.GetValue("foo", "bar");

因为这个实现涉及到大约1000行代码,有些情况下需要添加值为空的键,而该键被用作数据。例如: MyDict.Add("One_key", AnotherDictionary); MyDict.Add("Cool_key", null); 然后在for循环中: if(MyDict.value != null) //做某事你说得对,设计可能有点错误!但是我现在需要键和值字段来存储数据,而且我不想为这些键值对条目创建子字典,因为会增加代码开销,如果你知道我的意思的话。(许多空值条目) - N471v3

5

您可以这样做。在从主词典检索数据之后,您将需要将结果转换为适当的类型:

object obj;
If(mainDict.TryGetValue("key", out obj)) {
    var dict = obj as Dictionary<string, string>>;
    if (dict != null) {
        // work with dict
    } else {
        var value = obj as MyOtherType;
        ....
    }
}

但请注意,这种方法不是类型安全的;也就是说,编译器只能在某种程度上检查有关类型为object的值的代码的有效性。


或者你可以尝试更加面向对象的解决方案。

public abstract class MyBaseClass 
{
    public abstract void DoSomething();
}

public class MyDictClass : MyBaseClass
{
    public readonly Dictionary<string, string> Dict = new Dictionary<string, string>();

    public override void DoSomething()
    {
        // So something with Dict
    }
}

public class MyTextClass : MyBaseClass
{
    public string Text { get; set; }

    public override void DoSomething()
    {
        // So something with Text
    }
}

然后使用以下代码声明您的主字典:
var mainDict = new Dictionary<string, MyBaseClass>();

mainDict.Add("x", new MyDictClass());
mainDict.Add("y", new MyTextClass());

...

MyBaseClass result = mainDict[key];
result.DoSomething(); // Works for dict and text!

3

如果你在字典中使用对象作为值,可能会涉及一些风险和复杂性:

  • 缺乏类型安全性(任何内容都可以设置为值)
  • 必须将其强制转换为特定类型,可能基于值来转换

你应该重新考虑你的设计。但如果你真的需要灵活性,你可以创建一个新类型,作为值类型。例如:

class MySpecialType
{
    public Dictionary<string, string> MyStringDictionary { get; set; }
    public string MyStringVal {get; set;}

    public Type ActiveType { get; set; } // property would specify the current type
    // ...

你的主要字典声明应该类似于以下内容:
Dictionary<string, MySpecialType> MyDict = new Dictionary<string, MySpecialType>();

您可以使用ActiveType属性或创建一个指定类型的枚举。您还可以在类中使用静态工具函数来帮助返回正确的实例和类型...


你的回答结合其他人的知识对我来说最有意义(感谢!)在这种情况下,“缺乏类型安全性(任何东西都可以设置为值)”对我来说是一个特性:D你用类的解决方案很有道理,但对我来说有点像我试图避免的额外开销。所以问题解决了,感谢所有人,我的主要问题是代码的上下文和设计。谢谢 - N471v3

1

你将失去强类型和所有它们的好处。

你不能创建一个具有字典属性的新类,并将你的其他数据添加到其中吗:

public class CallItWhatYouLike
{
  public Dictionary<string, string> Dictionary {get; set;}
  public int AnotherProperty {get; set;}
  ...
}

var MyDict = new Dictionary<string, CallItWhatYouLike>();

0

没有问题。如果你需要将值输入为 Dictionary<string, string>,只需进行强制转换即可解决此问题。


0

嗯,你的代码将会少一些类型安全性,需要运行时类型检查和类型转换,但是你可以将object作为字典值类型并存储任何类型。


0

当您取消装箱System.Object时,会付出性能代价,但除此之外,您的方法没有问题,除了索引器过多的强制转换(由于弱类型)。

如果您使用的是.NET 4,则可以考虑使用System.Tuple


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接