gpt4 book ai didi

c# - 为什么不能将 IEnumerable 转换为 IEnumerable
转载 作者:IT王子 更新时间:2023-10-29 04:14:15 26 4
gpt4 key购买 nike

为什么不允许最后一行?

IEnumerable<double> doubleenumerable = new List<double> { 1, 2 };
IEnumerable<string> stringenumerable = new List<string> { "a", "b" };
IEnumerable<object> objects1 = stringenumerable; // OK
IEnumerable<object> objects2 = doubleenumerable; // Not allowed

这是因为 double 不是从对象派生的值类型,因此协方差不起作用吗?

这是否意味着没有办法使这项工作:

public interface IMyInterface<out T>
{
string Method();
}

public class MyClass<U> : IMyInterface<U>
{
public string Method()
{
return "test";
}
}

public class Test
{
public static object test2()
{
IMyInterface<double> a = new MyClass<double>();
IMyInterface<object> b = a; // Invalid cast!
return b.Method();
}
}

而且我需要自己编写 IMyInterface<T>.Cast<U>()这样做?

最佳答案

Why is the last line not allowed?

因为double是值类型,object是引用类型;协方差仅在两种类型都是引用类型时才有效。

Is this because double is a value type that doesn't derive from object, hence the covariance doesn't work?

没有。 Double 确实派生自对象。所有值类型都派生自对象。

现在你应该问的问题:

Why does covariance not work to convert IEnumerable<double> to IEnumerable<object>?

因为谁打拳击?从 double 到 object 的转换必须 box double。假设您调用 IEnumerator<object>.Current这“真的”是对 IEnumerator<double>.Current 实现的调用.调用者期望返回一个对象。被调用者返回一个 double 值。 执行将 IEnumerator<double>.Current 返回的 double 值的装箱指令的代码在哪里?变成盒装双人间?

它是无处,那是哪里,这就是为什么这种转换是非法的。调用Current将在评估堆栈上放置一个八字节的 double ,而消费者将期望在评估堆栈上有一个对装箱 double 的四字节引用,因此消费者将因堆栈未对齐而崩溃并死去以及对无效内存的引用。

如果您希望装箱的代码执行,则必须在某个时候编写,而您就是编写它的人。最简单的方法是使用 Cast<T>扩展方法:

IEnumerable<object> objects2 = doubleenumerable.Cast<object>();

现在调用包含装箱指令的辅助方法,该指令将 double 从八字节 double 转换为引用。

更新:一位评论者指出我提出了这个问题——也就是说,我通过假设存在一种机制来回答问题,该机制可以像解决原始问题所需的那样困难地解决问题。 Cast<T>如何执行设法解决是否装箱的问题?

它的工作原理就像这个草图。请注意,参数类型不是通用的:

public static IEnumerable<T> Cast<T>(this IEnumerable sequence) 
{
if (sequence == null) throw ...
if (sequence is IEnumerable<T>)
return sequence as IEnumerable<T>;
return ReallyCast<T>(sequence);
}

private static IEnumerable<T> ReallyCast<T>(IEnumerable sequence)
{
foreach(object item in sequence)
yield return (T)item;
}

确定从对象到 T 的转换是拆箱转换还是引用转换的责任被推迟到运行时。抖动知道T是引用类型还是值类型。 99% 的时间它当然是引用类型。

关于c# - 为什么不能将 IEnumerable<struct> 转换为 IEnumerable<object>?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9688268/

26 4 0