使用接口转换通用

Fra*_*k V 5 c# generics

我正在处理一个代码库,它通过类类型大量使用泛型.我一直在推动使用接口(出于各种原因).在我慢慢改变事物的工作中,我遇到了以下情况,我无法超越它.

简单地(并且最低限度地),我面临的问题如下:

private static IList<IDictionary<int, string>> exampleFunc()
{
    //The following produces a compile error of:
    // Cannot implicitly convert type 'System.Collections.Generic.List<System.Collections.Generic.Dictionary<int,string>>' to 
    //  'System.Collections.Generic.IList<System.Collections.Generic.IDictionary<int,string>>'. 
    // An explicit conversion exists (are you missing a cast?)  
    return new List<Dictionary<int, string>>(); 
}
Run Code Online (Sandbox Code Playgroud)

正如它在评论中所说,它会产生编译时错误.

如何生成符合可返回接口的对象?

一般来说,我如何转换或转换"内部"类型?


更新:我的例子可能会产生误导.我的情况并不特定于包含Dictionary元素的List.有一些例子,但它也可以IList<IVehicle> vehicleList = new List<Car>();

我的问题的关键是如何处理错配的通用类型.

Tim*_* S. 5

您的代码将无法工作,因为IList<T>不是covariant/contravariant

如果您自己创建列表,则可以为其指定兼容的类型:

private static IList<IDictionary<int, string>> exampleFunc()
{
    var list = new List<IDictionary<int, string>>();
    list.Add(new Dictionary<int, string>());
    return list;
}
Run Code Online (Sandbox Code Playgroud)

如果这不是一个选项,例如因为您从外部源获取它,那么您可以投射它。

private static IList<IDictionary<int, string>> exampleFunc()
{
    var list = new List<Dictionary<int, string>>();
    list.Add(new Dictionary<int, string>());
    return list.Cast<IDictionary<int, string>>().ToList();
}
Run Code Online (Sandbox Code Playgroud)

  • 首先,这只是创建“IDictionary”列表的一种更糟糕的方法。与方差无关。 (2认同)

Ser*_*rvy 5

您试图将其IList视为协变,这意味着您希望能够将泛型参数的所有实例视为实际上属于较少派生类型的实例.这IList是行不通的,因为它是不变的.(想象一下,如果有人SomeOtherTypeOfDictionary<int,string>在你回来的列表中添加了一个会发生什么.你现在已经把一些不属于你的东西Dictionary<int,string>List<Dictionary<int, string>>.

你可以返回一个IEnumerable<Dictionary<int, string>>协变的.

或者,如果您实际上没有已填充的列表,只需List<IDictionary<int, string>>从头开始创建相应类型()的列表.

另一种选择是创建一个列表并复制其中的所有元素return new List<Dictionary<int, string>>().Cast<IDictionary<int, string>>>().ToList();,虽然这通常不是很好的设计,特别是你还没有用数据填充列表.

所有这一切都假设你有一个真正令人信服的理由IList<IDictionary<int,string>>来开始.我声称确实没有令人信服的理由首先限制你ListDictionary相应的接口,并且返回a没有任何问题,List<Dictionary<int,string>>除非你确实有用于返回非List IList的用例或非字典ID.它使您的代码复杂化,为调用者删除了有价值的功能,如果您不打算返回该接口的不同实现,则不会真正增加价值.


Fra*_*k V 0

我已经找到了一种完成界面转换的方法。再次出现这种情况,回到我的字典列表示例(可以是任何数据类型——内置或自定义)。

class Program
{
    private static List<Dictionary<string, Guid>> GetList()
    {
        var myList = new List<Dictionary<string, Guid>>();
        for (var i = 0; i < 25; i++)
        {
            var newDict = new Dictionary<string, Guid>();
            for (var j = 0; j < 25; j++)
            {
                newDict.Add(j.ToString(), Guid.NewGuid());
            }
            myList.Add(newDict);
        }
        return myList;
    }
    //Really, I want the following to use interfaces; lets not worry about why there is a middle-man function.
    private static IList<Dictionary<string, Guid>> MyIntermediateFuncForAReason() 
    {
        var originalList = GetList();
        //whatever processing.
        return originalList;
    }
    static void Main(string[] args)
    {
        var t = MyIntermediateFuncForAReason();
        // whatever...
    }
}
Run Code Online (Sandbox Code Playgroud)

修改 将其MyIntermediateFuncForAReason转换为所需的类型,例如:

private static IList<IDictionary<string, Guid>> MyIntermediateFuncForAReason()
{
    var originalList = GetList();
    //whatever processing.
    return originalList.Select((IDictionary<string, Guid> i) => i).ToList();
}
Run Code Online (Sandbox Code Playgroud)