我真的只是将字符串数据类型放入IEnumerable <int>中

8 c# linq casting

好的,这有点奇怪.忽略我想要做的事情,并查看在这种情况下发生的结果.

代码:

static string rawNumbers="1,4,6,20,21,22,30,34";
static IEnumerable<int> numbers = null;

static void Main(string[] args)
{
    numbers = rawNumbers.Split(',').Cast<int>();

    for (int i = 0; i < numbers.Count(); i++)
    {
        //do something
    }

}
Run Code Online (Sandbox Code Playgroud)

情况:

该行numbers = rawNumbers.Split(',').Cast<int>(); 似乎有效,并且不会抛出任何异常.但是,当我遍历集合时,抛出InvalidCastException.

现在,深入了解源代码并查看CastIterator<TResult>.这似乎是for (int i = 0; i < numbers.Count(); i++)专门用来调用的numbers.Count()

static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source) {
    foreach (object obj in source) yield return (TResult)obj; 
}
Run Code Online (Sandbox Code Playgroud)

错误发生在演员表上,当我查看source变量中的数据时,它是一个字符串[].

我会想到,因为我调用强制转换为成功执行int的行所以一切都很好.幕后发生了什么?字符串数组真的只是存储在某个地方,并且在被调用之前没有被转换为T吗?懒惰的铸造也许?


我知道我不能这样做:(int)"42".我的问题不是如何使演员工作,而是发生了什么.演员的延期执行?看起来很奇怪,我呼唤的线Cast<int>()似乎工作,但实际上并没有.

Cod*_*lla 24

几件事情:第一,你不能一个stringint.您可以解析字符串并获得结果整数.但基本上你是在尝试这样做:

int x = (int)"32";
Run Code Online (Sandbox Code Playgroud)

那是一个例外. 其次,LINQ运算符是延迟执行的,所以在你尝试迭代结果之前没有任何实际发生,那就是真正的工作开始发生的时候.

使用延迟执行时,不会检查您请求的操作是有效还是可以正确执行,它只是设置操作,然后尝试在迭代时单独执行.

  • 我为你重要的部分:) (2认同)

And*_*ber 8

如前所述,"延期执行"是此处的问题.在迭代结果变量之前,许多LINQ运算符不会导致lambda代码实际执行.

其中一个原因是允许您构建一系列可以一次执行的复杂操作,而不是作为一系列单独的操作.这可能是一件有用的事情 - 但如果你不期待它也会很棘手.


jjn*_*guy 5

Cast看起来有效的原因是因为IEnumerable调用方法时不会枚举,而是在调用时枚举Count().所以,呼吁Cast()真的什么都不做.一旦实际评估了Cast,代码就会失败.

而不是试图施放,只需做一个简单的转换.

numbers = rawNumbers.Split(',').Select(str => int.parse(str));
Run Code Online (Sandbox Code Playgroud)


puf*_*pio 5

您没有立即在该Cast<int>()行发生错误的原因是因为记住这只是链接操作序列.只有在遍历集合后才会执行转换.

rawNumbers.Split(',')马上发生,但Cast<int>()延迟计算.

如果在该行上添加了ToList()或ToArray(),它将立即执行.