【问题标题】:C# Adding Generic List to a Dictionary [duplicate]C#将通用列表添加到字典[重复]
【发布时间】:2018-07-19 02:24:35
【问题描述】:

所以我在 C# 中遇到了通用列表的问题:

var foo = new Dictionary<long, List<object>>();
foo.Add(123, new List<string>());

给出错误:Cannot convert from System.Collections.Generic.List&lt;string&gt; to System.Collections.Generic.List&lt;object&gt;

在哪里可以正常工作:

var foo = new Dictionary<long, object>();
foo.Add(123, new string());

我的真实用例如下所示:

var foo = new Dictionary<long, List<ISomeInterface>>();
foo.Add(123, new List<SomeClassA>());
foo.Add(345, new List<SomeClassB>());

SomeClassA 和 SomeClassB 都实现了 ISomeInterface。这可能吗?

我的想法是我可以从字典中获取 ISomeInterface 列表并迭代调用在 ISomeInterface 上定义的 SomeMethod 的列表。

【问题讨论】:

  • 你想要的是协方差,它只适用于接口。所以Dictionary&lt;long, IEnumerable&lt;object&gt;&gt; 会起作用,但当然你只能从字典的值中取出项目,但这是为了确保你不会将字符串放入实际的 int 列表中。
  • 不确定这对您的情况是否有帮助,但您可以声明List&lt;ISomeInterface&gt; 类型的列表并用SomeObject 的实例填充它,然后将其添加到Dictionary跨度>
  • 如果您需要知道接口的具体类型,那就是代码异味。您应该通过接口的 API 将任何类似的类类型逻辑推送到类中。
  • @juharr 说的是对的,但你也可以使用Dictionary&lt;long, IReadOnlyList&lt;ISomeInterface&gt;&gt;

标签: c# generics


【解决方案1】:

您可以使用ToList 将类转换为泛型类型接口,如

using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp9
{
    class Program
    {
        static void Main(string[] args)
        {
            Dictionary<int, List<ISomething>> dictionary
                = new Dictionary<int, List<ISomething>>();

            var list = new List<Something>() { new Something() };
            dictionary.Add(1, list.ToList<ISomething>());
        }

        public interface ISomething
        {
        }

        public class Something : ISomething
        {
        }
    }
}

【讨论】:

  • 谢谢。 ToList&lt;ISomething&gt;() 虽然对某些人来说可能很明显,但这正是我所需要的,也是最简单的解决方案。
【解决方案2】:

对于您的实际用例:

您需要将您的列表声明为List&lt;ISomeInterface&gt;,然后用实现此类接口的对象填充它。

var foo = new Dictionary<long, List<ISomeInterface>>();
foo.Add(123, new List<ISomeInterface>());
foo[123].Add(new SomeObjectThatImplementsISomeInterface());

另一种方法是先创建列表,然后将其添加到字典中。

var bar = new List<ISomeInterface>();
bar.add(new SomeObjectThatImplementsISomeInterface());
bar.add(new SomeOtherObjectThatImplementsISomeInterface());
var foo = new Dictionary<long, List<ISomeInterface>>();
foo.Add(123, bar);

当然,当您从foo 取回值时,您会得到ISomeInterface,如果您需要知道此类对象的具体类型,则需要进行反射。

【讨论】:

  • 反映或只是.Cast&lt;&gt;()
  • @r1verside 更好的是通过接口 API 将这种类型的逻辑推送到类中,这样您就不需要反射或强制转换。
  • @r1verside 我在 OP 的 cmets 中理解的是他需要知道类型。如果他知道或期望一个特定的,他可以投射它,但正如 juharr 提到的那样,这并不是接口的真正用途。
  • 我需要知道接口类型,以便在迭代列表时调用共享方法。这个答案似乎最好有一个变化,而不是foo[123].Add() do foo[123].AddRange()
  • @Shane 如果您已经拥有该列表,则只需将其添加到字典中,而不是创建然后填充它。我会更新我的答案。
【解决方案3】:

您可以使用 System.Linq 解决它:

var foo = new Dictionary<long, List<object>>();
foo.Add(123, new List<string>().ToList<object>());

同样,

var foo = new Dictionary<long, List<ISomeInterface>>();
foo.Add(123, new List<SomeObject>().ToList<ISomeInterface>());

另一种可能性:

foo.Add(123, new List<ISomeInterface>(new List<SomeObject>()));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-31
    • 2016-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-24
    • 1970-01-01
    相关资源
    最近更新 更多