具有字典和枚举的嵌套泛型

本文关键字:嵌套 泛型 枚举 字典 | 更新日期: 2023-09-27 17:49:29

在一个内部可重用库的通用c#类中,我想传递一个引用到"映射到其他事物列表的东西"。在那里传递的数据类型不应该被库所知道。此外,它们的存储方式也不应该是已知的,也就是说,今天保存在内存中的列表,将来可能是一个按需读取的数据库表。

所以我想我应该写这个库类:

class GenericClass<T, U>
{
    public void Foo(IDictionary<T, IEnumerable<U>> bar)
    {
        // do something
    }
}

这可以编译,但试图传递具体的实现却不能:

class UsingClass
{
    public static void Main(string[] args)
    {
        var c = new GenericClass<string, string>();
        c.Foo(new Dictionary<string, List<string>>());
    }
}

我得到以下两个语法错误:

Filename.cs(46,13): error CS1502: The best overloaded method match for 'GenericClass<string,string>.Foo(System.Collections.Generic.IDictionary<string,System.Collections.Generic.IEnumerable<string>>)' has some invalid arguments
Filename.cs(46,19): error CS1503: Argument 1: cannot convert from 'System.Collections.Generic.Dictionary<string,System.Collections.Generic.List<string>>' to 'System.Collections.Generic.IDictionary<string,System.Collections.Generic.IEnumerable<string>>'

List替换Foo()声明上的IEnumerable修复它,但这当然不是我想要的。

这是真的不支持c#(4.0)还是我只是错过了一些明显的东西?你有什么建议?(我相信这一点之前已经讨论过很多次了,所以链接到优秀的描述也很好。)

是的,我应该能够为此编写自己的助手类,但为什么我必须这样做?

具有字典和枚举的嵌套泛型

是的,这确实不支持。假设你的Foo方法是这样的:

public void Foo(IDictionary<T, IEnumerable<U>> bar)
{
    T key = GetKeyFromSomewhere();
    bar[key] = new U[10]; // Create an array
}

看起来不错,不是吗?我们可以从U[]转换为IEnumerable<U>

从调用者的角度来看,这并不是很好——突然我们在字典中得到了一个string[]引用值,而所有的值都应该是List<string>引用!Bang goes type safety.

您可以将该方法重写为:

public void Foo<TValue>(IDictionary<T, TValue> bar)
    where TValue : IEnumerable<U>

这将使您获得值的字典,并将它们隐式地转换为IEnumerable<U>…但是你只能将正确类型的值放入字典中,而不能仅从U值构建

从版本4开始,c#在受限的情况下支持泛型方差。例如,这可以在c# 4中工作(当目标是。net 4时),但以前不能:

List<string> strings = new List<string>();
IEnumerable<object> objects = strings;

有关通用方差的更多信息,请参阅Eric Lippert关于该主题的博客系列。做好大脑周期性爆炸的准备。