显式强制转换存在,但似乎不适用于Dictionary到字典

本文关键字:int string IEnumerabl 字典 Dictionary 不适用 转换 存在 适用于 | 更新日期: 2023-09-27 18:17:57

使用隐式强制转换编写代码生成CS0266。

Dictionary<Int32, string[]> d1 = new Dictionary<int, string[]>();
IDictionary<int, IEnumerable<string>> ide1 = d1; // CS0266

存在显式强制转换的提示表明显式强制转换可以解决这个问题。

IDictionary<int, IEnumerable<string>> ide1 = (IDictionary<int, IEnumerable<string>>)d1; // No error, but throws an exception

有办法让这个cast吗?对于string[][]IEnumerable<IEnumerable<string>>是否有效?

namespace Quickie
{
    class QuickieArray
    {
        private static void TestCastDictionaryWithArrayValue()
        {
            Console.WriteLine();
            Console.WriteLine("===TestCastDictionaryWithArrayValue===");
            Dictionary<Int32, string[]> d1 = new Dictionary<int, string[]>();
            d1[1] = new string[]{"foo"};
            IDictionary<int, string[]> id1 = d1;
            Console.WriteLine("id1 is null: {0}", id1 == null);
            IDictionary<int, IEnumerable<string>> ide1 = id1 as IDictionary<int, IEnumerable<string>>;
            IDictionary<int, IEnumerator<string>> iden1 = id1 as IDictionary<int, IEnumerator<string>>;
            Console.WriteLine("ide1 is null: {0}", ide1 == null);
            Console.WriteLine("iden1 is null: {0}", iden1 == null);
            Console.WriteLine();
        }
        internal static void Test()
        {
            Console.WriteLine();
            Console.WriteLine("=QuickieArray=");
            TestCastDictionaryWithArrayValue();
        }
    }
}
输出:

= = = TestCastDictionaryWithArrayValue = = =
id1是null: False
ide1是null: True
iden1 is null: True

显式强制转换存在,但似乎不适用于Dictionary<int, string[]>到字典<int, IEnumerabl

这是一个经典的协方差/逆变问题。我将向您展示一个简化的示例来证明为什么Dictionary<Int32, string[]>而不是IDictionary<int, IEnumerable<string>>不能将转换为一个。

让我们暂时假设所讨论的强制转换有效,并且编译以下代码:

Dictionary<int, string[]> arrayDictionary = new Dictionary<int, string[]>();
IDictionary<int, IEnumerable<string>> enumerableDictionary = arrayDictionary;

现在,我们有一个对象。很明显是Dictionary<int, string[]>类型的。我们有两个对它的引用,一个是Dictionary<int, string[]>类型,另一个是IDictionary<int, IEnumerable<string>>类型。

如果后面跟着这段代码会发生什么?

List<string> stringList = new List<string>();
enumerableDictionary.Add(0, stringList);

如果我们可以按照您想要的方式转换Dictionary<int, string[]>,那么上面的代码段将成功编译…

…然后在运行时爆炸。为什么?因为List<string> 不是 string[] .

enumerableDictionaryAdd方法接受任何IEnumerable<string>,但是创建的真实的对象(Dictionary<int, string[]>)有一个方法,只有接受string[]

这就是为什么Dictionary<Int32, string[]>而不是IDictionary<int, IEnumerable<string>>不能强制转换为一个

没有,也不应该有。想象下面的内容:

        Dictionary<Int32, string[]> d1 = new Dictionary<int, string[]>();
        IDictionary<int, IEnumerable<string>> ide1 = d1; 
        ide1.Add(99,new List<string>());

虽然第三行对于IDictionary<int, IEnumerable<string>>来说是完全可以接受的,但是对于IDictionary<int, string[]>来说是不可接受的。

正如@adam-maras和@d-stanley所说,这是一个协方差问题。因此,尽可能使用接口。例如,使用IDictionary<Int32, IEnumerable<string>>作为派生较少的类型来保存用派生较多的类型实例化的数据:

using System;
using System.Collections.Generic;
namespace Quickie
{
    class QuickieArray
    {
        private static void TestCastIDictionaryWithArrayValue()
        {
            Console.WriteLine();
            Console.WriteLine("===TestCastIDictionaryWithArrayValue===");
            IDictionary<int, IEnumerable<string>> d1 = new Dictionary<int, IEnumerable<string>>();
            d1[1] = new string[] { "foo" };
            IDictionary<int, IEnumerable<string>> id1 = d1;
            Console.WriteLine("id1 is null: {0}", id1 == null);
            IDictionary<int, IEnumerable<string>> ide1 = id1 as IDictionary<int, IEnumerable<string>>;
            IDictionary<int, IEnumerator<string>> iden1 = id1 as IDictionary<int, IEnumerator<string>>;
            Console.WriteLine("ide1 is null: {0}", ide1 == null);
            Console.WriteLine("iden1 is null: {0}", iden1 == null);
            Console.WriteLine();
        }
        internal static void Test()
        {
            Console.WriteLine();
            TestCastIDictionaryWithArrayValue();
        }
    }
}

至于显式强制转换存在吗?不,没有。

像这样的东西也可以工作就像一个例子在我的例子中,我从逗号分隔字段读取

var intFileCount = 0;
Dictionary<int, string[]> dctListRecords = null; 
//initialize a capacity if you want 
dctListRecords = new Dictionary<int, string[]>(strLinesStockRecord.Count());
foreach (string strLineSplit in strLinesStockRecord)
{
  lstSplitList2 = strLineSplit.Split(chrCOMMA_SEP).ToList();
  dctListRecords.Add(intFileCount, lstSplitList2.ToArray());
  //this allows you to use the string value inside of string[]
  lstSplitList2.Clear();
  intFileCount++;
}