Linq ToDictionary 不会将类隐式转换为接口

Kez*_*zza 5 c# linq todictionary

我有以下代码

public class TestAdaptor
{
    private interface ITargetClass
    {
        Guid Id { get; }

        string Name { get; }
    }

    private class MyTargetClass : ITargetClass
    {
        public Guid Id { get; private set; }

        public string Name { get; private set; }

        public MyTargetClass(MySourceClass source)
        {
        }
    }

    private class MySourceClass
    {
        public Guid Id { get; set; }

        public string Name { get; set; }
    }

    private Dictionary<Guid, IEnumerable<ITargetClass>> ConvertItems(Dictionary<Guid, IEnumerable<MySourceClass>> source)
    {
        return source.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Select(v => new MyTargetClass(v)));
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,这不会编译,因为 ToDictionary 行会导致以下错误

Cannot implicitly convert type
'System.Collections.Generic.Dictionary<System.Guid,System.Collections.Generic.IEnumerable<TestAdaptor.TestAdaptor.MyTargetClass>>'
to
'System.Collections.Generic.Dictionary<System.Guid,System.Collections.Generic.IEnumerable<TestAdaptor.TestAdaptor.ITargetClass>>'   ...\TestAdaptor.cs  38  20
Run Code Online (Sandbox Code Playgroud)

现在很明显 MyTargetClass 实现了 ITargetClass 但编译器没有选择它。

现在我明确地转换 (ITargetClass)new MyTargetClass(v)

但是为什么首先会发生这种情况,有没有更好的方法来解决这个问题?

Phi*_*tle 5

编译器不会自动转换IEnumerable<X>IEnumerable<Y>Even ifX : Y因为IDictionary不是协变的。这里讨论其基本原理:IDictionary<,> 逆变?.NET 4 中的IDictionary <TKey, TValue> 不是协变的

至于绕过它,就像你提到的,你必须施放:

使用 Cast 扩展方法:

 kvp => kvp.Value.Select(v => new MyTargetClass(v)).Cast<ITargetClass>()
Run Code Online (Sandbox Code Playgroud)

显式转换:

 kvp => kvp.Value.Select(v => (ITargetClass) new MyTargetClass(v))
Run Code Online (Sandbox Code Playgroud)

更新

只是为了扩展这一点,因为IEnumerable和之间存在混淆IDictionaryIEnumerable 协变的。IDictionary 不是

这很好:

 IEnumerable<ITargetClass> list = new List<MyTargetClass>();
Run Code Online (Sandbox Code Playgroud)

这不是:

 IDictionary<object, IEnumerable<ITargetClass>> dict = 
     new Dictionary<object, List<MyTargetClass>>();
Run Code Online (Sandbox Code Playgroud)

IDictionary继承自IEnumerable<KeyValuePair<TKey, TValue>>. 问题在于哪个KeyValuePair不是协变的,哪个使得IDictionary不是协变的。