.Cast<T> 扩展方法总是抛出 InvalidCastException - 你应该如何使用这个方法?
.Cast<T> extension method always throws InvalidCastException - How are you supposed to use this method?
有几次我对 .Cast<T>
LINQ 扩展方法感到好奇。我心想 "that sounds like just what I need in this situation" 但每当我尝试使用它时,我总是得到一个 InvalidCaseException
。我从来没有能够成功地使用这种方法。这是检查异常的示例行:
Enumerable.Range(0,10).Cast<float>().ForEach(Console.Out.WriteLine);
将int
转换为float
没有什么争议,那么为什么这种方法拒绝这样做呢?我可以解决这个问题并通过简单地将 .Cast<float>
替换为 .Select(x => (float)x)
来获得所需的效果
Enumerable.Range(0, 10).Select(x => (float)x).ForEach(Console.Out.WriteLine);
这不是太麻烦,但我仍然不明白为什么 Cast<float>
方法不能为我完成这项工作。
问题简而言之:如何使用 .Cast<T>
扩展方法?
这与问题无关,但以防万一有人想知道,我在上面的代码片段中使用了自定义 ForEach 扩展方法(标准方法仅适用于列表):
static class Extensions
{
public static void ForEach<T>(this IEnumerable<T> x, Action<T> l)
{
foreach (var xs in x) l(xs);
}
}
当您写下以下内容时:
int a = GetInt();
var b = (float)a;
你实际上并没有铸造价值。你正在转换它。 C# 只是为您提供了很好的语法。此处生成的 IL 是 conv.r4
,它将堆栈顶部的值转换为浮点数。
Enumerable.Cast<T>
实际上是在进行转换,并没有得到语法糖的好处。
如果你写:
Enumerable.Range(0,10).Cast<object>().ForEach(Console.Out.WriteLine);
你会没事的,因为一个整数是可转换为一个对象。
如果你查看 ReferenceSource 的 Cast<TResult>
方法的源代码,你会看到最后 CastIterator<TResult>
方法被调用,类似于:
static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source)
{
foreach (object obj in source) yield return (TResult)obj;
}
如您所见,C# 尝试从 boxed 对象转换为 TResult
,这是异常的原因。如果您想模仿问题,请尝试以下操作:
int a = 5;
object o = a;
float f = (float)o;
有几次我对 .Cast<T>
LINQ 扩展方法感到好奇。我心想 "that sounds like just what I need in this situation" 但每当我尝试使用它时,我总是得到一个 InvalidCaseException
。我从来没有能够成功地使用这种方法。这是检查异常的示例行:
Enumerable.Range(0,10).Cast<float>().ForEach(Console.Out.WriteLine);
将int
转换为float
没有什么争议,那么为什么这种方法拒绝这样做呢?我可以解决这个问题并通过简单地将 .Cast<float>
替换为 .Select(x => (float)x)
Enumerable.Range(0, 10).Select(x => (float)x).ForEach(Console.Out.WriteLine);
这不是太麻烦,但我仍然不明白为什么 Cast<float>
方法不能为我完成这项工作。
问题简而言之:如何使用 .Cast<T>
扩展方法?
这与问题无关,但以防万一有人想知道,我在上面的代码片段中使用了自定义 ForEach 扩展方法(标准方法仅适用于列表):
static class Extensions
{
public static void ForEach<T>(this IEnumerable<T> x, Action<T> l)
{
foreach (var xs in x) l(xs);
}
}
当您写下以下内容时:
int a = GetInt();
var b = (float)a;
你实际上并没有铸造价值。你正在转换它。 C# 只是为您提供了很好的语法。此处生成的 IL 是 conv.r4
,它将堆栈顶部的值转换为浮点数。
Enumerable.Cast<T>
实际上是在进行转换,并没有得到语法糖的好处。
如果你写:
Enumerable.Range(0,10).Cast<object>().ForEach(Console.Out.WriteLine);
你会没事的,因为一个整数是可转换为一个对象。
如果你查看 ReferenceSource 的 Cast<TResult>
方法的源代码,你会看到最后 CastIterator<TResult>
方法被调用,类似于:
static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source)
{
foreach (object obj in source) yield return (TResult)obj;
}
如您所见,C# 尝试从 boxed 对象转换为 TResult
,这是异常的原因。如果您想模仿问题,请尝试以下操作:
int a = 5;
object o = a;
float f = (float)o;