【问题标题】:Heterogeneous Dictionary, but typed?异构字典,但输入?
【发布时间】:2008-11-27 12:32:44
【问题描述】:

这更像是一个学术探究,而不是一个实际问题。是否有任何语言或框架功能可以或将来允许异构类型的字典,例如

myDict.Add("Name", "Bill"); 
myDict.Add("Height", 1.2); 

myDict 现在包含的不是两个 object 类型作为值,而是一个 string 和一个 double?然后我可以用

检索我的double
double dbl = myDict["Height"];

并期望抛出一个双精度或异常?

请注意:名称和高度值不一定属于同一对象。

【问题讨论】:

    标签: .net


    【解决方案1】:

    如果您有一个自定义集合,其中包含 Add 和 Get 方法的泛型重载,那么您将能够做到这一点的唯一方法。但这意味着您在读取密钥时可能会要求输入错误的类型,因此在调用 Get 方法时自己进行转换并不会为您带来太多(如果有的话)。

    但是,如果您可以将泛型类型推送到键中,那么这可能会起作用。类似的东西(这里是未经测试的代码)

    sealed class MyDictionaryKey<T>
    {
    }
    
    class MyDictionary
    {
        private Dictionary<object, object> dictionary = new Dictionary<object, object>();
    
        public void Add<T>(MyDictionaryKey<T> key, T value)
        {
            dictionary.Add(key, value);
        }
    
        public bool TryGetValue<T>(MyDictionaryKey<T> key, out T value)
        {
          object objValue;
          if (dictionary.TryGetValue(key, out objValue))
          {
            value = (T)objValue;
            return true;
          }
          value = default(T);
          return false;
        }
    
        public T Get<T>(MyDictionaryKey<T> key)
        {
          T value;
          if (!TryGetValue(key, out value))
             throw new KeyNotFoundException();
          return value;
        }
    }
    

    然后你可以像这样定义你的键:

    static readonly MyDictionaryKey<string> NameKey = new MyDictionaryKey<string>();
    static readonly MyDictionaryKey<double> HeightKey = new MyDictionaryKey<double>();
    

    并像使用它

    var myDict = new MyDictionary();
    myDict.Add(NameKey, "Bill"); // this will take a string
    myDict.Add(HeightKey , 1.2); // this will take a double
    
    string name = myDict.Get(NameKey); // will return a string
    double height = myDict.Get(HeightKey); // will return a double
    

    【讨论】:

    • 谢谢。正如其他人所说,这与其说是一种实际的调查,不如说是学术调查,但你在推断我想要确定检索到的项目的预期类型时一针见血。
    【解决方案2】:

    您可以使用通用Dictionary&lt;object, object&gt;;键的对象类型和值的对象类型。 C# 可以提供帮助。

    【讨论】:

      【解决方案3】:

      键都是字符串?那么Dictionary&lt;string,object&gt; 可能会完成这项工作......但是在获取值时,您需要使用object,或者您需要强制转换:

      double dbl = (double)myDict["Height"];
      object height = myDict["Height"];
      

      【讨论】:

      • 我问这个问题的真正原因是避免将 dic 值作为对象。如果我存储一个替身,我想要一个替身,而不是我必须投射的“双重暴露对象”。
      • @Profk - 如果您认为 Get(...) 与 (int) Get(...) 有任何不同,那您就是在自欺欺人。哦,好吧...
      • @MarcGravell 不正确。如果类在插入时在内部强制类型与其值之间的关联,则需要内部强制转换的检索将是完全安全的(不是编译器安全的,但假设代码在内部是正确的,则安全)。没有外部调用者能够根据键/值类型不匹配导致无效转换。他们要么得到一个类型化的值,要么得到一个空值,从他们的角度来看,这将是完全类型安全的。理论上,不会发生无效的强制转换异常,无论是在容器内部,还是在容器外部。
      • @AaronHS 我看不出这有什么不同;在这种情况下,(int)Get(...)Get&lt;int&gt;(...) 都可以工作,但它们已经一起工作(或不工作)。我们所做的只是移动演员阵容。因为有人输入错误而返回 null 是一个糟糕的举动。 正确的事情是:一个无效的强制转换异常。
      • @MarcGravell 的问题不是somebody got the type wrong。问题是有人天真地将键与一种类型的值关联起来,比如string: (1) dict.Add("myKey!", "myStringValue!")。然后,同一个人尝试检索该值: (2) string unsafeStr = (string)dict["myKey!"]bang 发生强制转换异常。但为什么?其他人认为myKey!int 值的一个很好的键,并且在(1) 和(2) 之间的某个地方执行了这行代码:dict["myKey!"] = 123。这里,(string)Get 失败,但 Get&lt;String&gt; 成功并保持一致性。
      【解决方案4】:

      如果类型是类,则没有什么可以阻止您与两者交互并将实例放入字典

      【讨论】:

      • 也许吧。也许像 IPresentationElementValue 这样的东西。值得深思。
      【解决方案5】:

      字典不是这样做的方法。
      您确实需要一个 Person 类来存储这些值。

      而且,使用类创建集合和捕获错误要容易得多。

      编辑:

      因为你需要一个半强类型的字典:

      public class CustomDictionary : Dictionary<string,object>
      {
          public T GetTyped<T>(string key) where T : IConvertible
          {
              return (T)Convert.ChangeType(base[key], typeof (T));
          }
      }
      

      用法:

      CustomDictionary dictionary = new CustomDictionary();
      
      dictionary.Add("Test",1.2);
      
      var d = dictionary.GetTyped<double>("Test");
      

      【讨论】:

      • 这些值不需要耦合到同一个对象,正如我的示例意外暗示的那样。名字可以是狗的名字,高度可以是桌子的名字。
      • 哦,好的。您想要一个扩展 Dictionary 并添加 GetTyped(string key) 方法的 CustomDictonary :)
      【解决方案6】:

      有什么理由你不能创建一个类/结构并将其放入列表或字典中?否则,您可以用自己的字典类包装字典并以这种方式设置限制。

      【讨论】:

        【解决方案7】:

        为什么不简单地将所有值存储为字符串,在检索它们时对其进行转换,并从该转换中捕获异常?

        我不明白您为什么需要以这种方式做事 - 也许需要重新设计您的程序?

        【讨论】:

        • 我不需要这样做。除了探索可以做什么之外,我不需要做任何事情。
        【解决方案8】:

        字典将包含一个字符串和一个双精度值作为值,但双精度值将被装箱。

        编译器如何验证您的要求?它如何在编译时知道每个键对应的对象类型?

        【讨论】:

        • 思路不是在编译时就知道,而是用key来确定返回类型。 C# 正朝着包含一些令人兴奋的动态概念的方向发展,我相信这可能会受到影响。
        猜你喜欢
        • 1970-01-01
        • 2010-11-22
        • 1970-01-01
        • 2022-07-29
        • 2021-04-18
        • 1970-01-01
        • 2020-06-24
        • 1970-01-01
        • 2012-12-13
        相关资源
        最近更新 更多