【问题标题】:Dictionary of generic lists or varying types通用列表或不同类型的字典
【发布时间】:2011-02-18 05:37:07
【问题描述】:

我想要一个将字符串映射到不同类型的通用列表的字典。即采用以下形式:

键值 字符串列表 字符串列表 字符串列表 字符串列表 ...

目前我正在使用Dictionary<string, IList>,然后从每个字典KeyValuePair<string, IList> pair 条目中提取强类型列表,如下所示:

Type layerType = pair.Value.GetType().GetGenericArguments()[0];
List<layerType> objectsClicked = pair.Value as List<layerType>;

有更好的方法吗?

[编辑] 正如已经指出的那样,上面没有编译,道歉 - 这就是你在做某事时提出问题时得到的结果。 更多的解释。我正在制作一个基本的空间数据查看器。最终视图由一组Layer&lt;T&gt;s 组成。每个层都提供了一个委托来渲染其类型(给定偏移量和比例)以及一种检查其哪些对象在当前窗口中的方法。对于命中测试,我想要每个被命中对象的图层的列表。该列表将是 List&lt;Point&gt; 用于 Point 层等...然后将来自所有 Layer&lt;T&gt;s 的命中分组为强类型列表的集合。

【问题讨论】:

  • 提供的代码示例无法编译。无论如何,如果您能告诉我们 a) 列出清单后您将如何处理 b) 您要解决的更大问题是什么,那将非常有帮助。
  • 你所拥有的不会编译。您不能将类型对象作为泛型类型参数传递。如果您不以强类型方式访问列表,为什么还需要泛型?
  • 既然你把这些列表放在同一个字典里,它们之间肯定有一些共同点(例如它们有相同的基类/接口什么的)。您应该提供更多信息。

标签: c#


【解决方案1】:

假设您使用 C# 4,Dictionary&lt;string, dynamic&gt; 怎么样

Dictionary<string, dynamic> Dict = new Dictionary<string, dynamic>();
Dict.Add("int", new List<int>());
Dict.Add("string", new List<string>());

Dict["int"].Add(12);
Dict["string"].Add("str");

foreach (KeyValuePair<string, dynamic> pair in Dict) {
   Type T = pair.Value.GetType();
   Console.WriteLine(T.GetGenericArguments()[0].ToString());
}

打印出来

System.Int32

系统字符串

这就是你要找的吗?

【讨论】:

  • 我认为他的 Dictionary 要好得多。不要将他与动态混淆。
  • 是的,您可以使用 Dictionary 进行操作,但是您必须在每次访问时都进行一次强制转换你的字典里面的东西,以便操纵列表。很多人以动态语言为生,我认为在情况需要时偶尔在 C# 中使用动态类型不会杀死任何人。我认为一些语言纯粹主义者需要冷静一下
  • @Adam - 我给了你一个赞成票,你的解决方案很好,但 Euphoric 还没有找到泛型,所以我不会尝试将他与动力学混淆。
  • 我很了解泛型,谢谢。问题是 C# 是静态类型语言。 dynamic 被添加到 .NET 中用于动态语言,并添加到 C# 中以获得“酷”因素。我认为动态在 C# 之类的语言中没有地位,因为它除了在代码中增加不必要的复杂性之外什么也没有。
  • 动态的作用远不止“酷因素”。它允许鸭子类型、“扩展”对象和简化反射。如果你再发表这样的贬低言论,我会派 Eric Lippert 追你……
【解决方案2】:

我打算在 Euphoric 和 Adam 之间取一个中间地带,你应该同时使用 IListdynamic。这是我认为更正确的:

var dict = new Dictionary<string, IList>();
dict.Add("u", new List<U>());
dict.Add("v", new List<V>());

// in case of members you know they exist on an IList
dict["u"].Add(new U());
dict["v"].Add(new V());

// in case you know what you are going to get back, in which case you should cast
var uProperty = (dict["u"][0] as U).UProperty
var vProperty = (dict["v"][0] as V).VProperty

// in case your're not sure of     
(dict[someKey] as dynamic)[someIndex].SomeMember...;

所有这些都比依赖反射简单得多。基本思想是将字典值类型声明为IList,以使您的意图更清晰,同时使用dynamic 来缓解反射怪物并缩短代码。

【讨论】:

    【解决方案3】:

    使用Dictionary&lt;string, IList&gt; 可能是唯一的解决方案。但是你的代码是错误的,你不能使用这样的泛型。你不能像这样动态地创建类型。

    您需要的一般问题是它与 C# 等强类型语言不兼容。在强类型语言中,您必须确切知道什么类型是类型。但是这不能使用正常的手段来完成。您对泛型的理解也是错误的。它对该类型的唯一编译时扩展。

    总体思路:在您的情况下,使用您保存在这些列表中的某种类型的 OOP 层次结构。这将是一个更好、更安全的想法,并且不会让每个看到你的代码的人都抓狂。

    【讨论】:

    • 这种需要类型系统灵活性的情况正是动态设计的目的(除其他外,例如更容易的反射)。
    【解决方案4】:

    我实际上认为更简洁的方法是为您的字典创建一个包装器:

    public class GlobalStore
    {
        private readonly IDictionary<Type, IEnumerable> _globalStore;
    
        public GlobalStore()
        {
            _globalStore = new ConcurrentDictionary<Type, IEnumerable>();
        }
    
        public IEnumerable<T> GetFromCache<T>()
            where T : class 
        {
            return (IEnumerable<T>) _globalStore[typeof(T)];
        }
    
        public void SetCache<T>(IEnumerable<T> cache)
            where T : class
        {
            _globalStore[typeof(T)] = cache;
        }
    }
    

    这是一个测试:

    [TestClass]
    public class GlobalStoreTest
    {
        [TestMethod]
        public void GlobalStore_Test()
        {
            //Arrange
            var globalStore = new GlobalStore();
            globalStore.SetCache(new List<ClientModel>
            {
                new ClientModel
                {
                    ClientId = 1,
                    ClientName = "Client1"
                },
                new ClientModel
                {
                    ClientId = 2,
                    ClientName = "Client2"
                }
            });
    
            //Act
            var clients = globalStore.GetFromCache<ClientModel>();
    
            //Assert
            Assert.AreEqual(2, clients.Count());
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-03-27
      • 2010-10-16
      • 1970-01-01
      • 2019-08-29
      • 1970-01-01
      • 1970-01-01
      • 2023-03-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多