gpt4 book ai didi

c# - 为什么 C# 编译器允许使用 Linq 而不是使用括号执行强制转换?

转载 作者:行者123 更新时间:2023-11-30 13:10:33 25 4
gpt4 key购买 nike

我有一个通用类 NamedValue<TValue> :

public class NamedValue<TValue>
{
public string Name { get; set; }
public TValue Value { get; set; }
}

我有第二个通用类,NamedValueSource<TValue>包含 List<NamedValue<TValue>> :

public class NamedValueSource<TValue>
{
public List<NamedValue<TValue>> NamedValues { get; set; }

public NamedValueSource()
{
NamedValues = GetNamedValues().Cast<NamedValue<TValue>>().ToList();
}

private IEnumerable<NamedValue<bool>> GetNamedValues()
{
var yesNamedValue = new NamedValue<bool> { Name = "Yes", Value = true };
var noNamedValue = new NamedValue<bool> { Name = "Yes", Value = false };
yield return yesNamedValue;
yield return noNamedValue;
}
}

以下测试代码完美运行(断言通过):

public class Tester
{
public Tester()
{
var source = new NamedValueSource<bool>();
Debug.Assert(source.NamedValues[0].Name == "Yes");
}
}

现在,这是有趣的部分。如果我尝试在 GetNamedValues() 内执行转换,代码将无法编译:

public class NamedValueSourceFail<TValue>
{
public List<NamedValue<TValue>> NamedValues { get; set; }

public NamedValueSourceFail()
{
NamedValues = GetNamedValues().ToList();
}

private IEnumerable<NamedValue<TValue>> GetNamedValues()
{
var yesNamedValue = new NamedValue<bool> { Name = "Yes", Value = true };
var noNamedValue = new NamedValue<bool> { Name = "Yes", Value = false };
yield return (NamedValue<TValue>)yesNamedValue; // ERROR: cannot convert type
yield return (NamedValue<TValue>)noNamedValue; // ERROR: cannot convert type
}
}

为什么 NamedValueSource<TValue>编译 NamedValueSourceFail<TValue>出错了吗?具体来说,为什么我可以使用 Linq 执行转换但不能使用好的 ol'parantheses?

编辑

如果从已接受答案的评论线程中看不清楚,我只需要转换为 object首先,然后我将被允许转换为 NamedValue<TValue> .这可能是 Linq Cast 的方式方法在幕后起作用。

最佳答案

更新:这个问题是the subject of my blog on July 10th 2012 ;谢谢你的好问题!


让我们大大简化您的复杂程序。

public static class X
{
public static V Cast<V>(object o) { return (V)o; }
}

class C<T> {}
class D<U>
{
public C<U> value;
public D()
{
this.value = X.Cast<C<U>>(new C<bool>());
}
}

现在是您的第二个版本,经过简化:

class C<T> {}
class D<U>
{
public C<U> value;
public D()
{
this.value = (C<U>)(new C<bool>());
}
}

好的,现在让我们问一些问题。

Why does the second program fail at compile time?

因为没有从 C<bool> 进行转换至 C<U>任意 U .编译器知道这可能成功的唯一方式是U 总是 bool,因此这个程序几乎肯定是错误的!编译器假定 U有时会是 bool 以外的东西。

Why then does the first program succeed at compile time?

编译器不知道为了错误检测的目的,一个名为“X.Cast”的方法应该被当作一个转换运算符来对待!就编译器而言,Cast method 是一种接受对象并返回 V 的方法。对于为 V 提供的任何类型参数.在编译 D 的构造函数的主体时,编译器根本不知道某些方法(可能甚至不在该程序中开始)将尝试执行将失败的强制转换,除非 U。恰好是 bool 值。

编译器根本没有将第一个版本视为错误的依据,即使它肯定是一个严重错误的程序。您必须等到运行时才能发现您的程序有误。

现在让我们制作程序的第三版本:

class C<T> {}
class D<U>
{
public C<U> value;
public D()
{
this.value = (C<U>)(object)(new C<bool>());
}
}

这在编译时成功了,所以让我们问:

Why does this succeed at compile time?

与第一个在编译时成功的原因完全相同。当你插入类型转换时,你实际上说你想要新建的 C<bool>被视为对象,因此对于此表达式的其余分析,该表达式被视为对象类型,而不是更具体的类型 C<bool> .

So then why is it legal to cast object to C<U> in this case? Or for that matter, to V in the first case?

将对象转换为V是合法的因为V可能是对象的类型、对象的基类型或对象实现的接口(interface),因此编译器允许转换,因为它认为有很多方法可能成功。

基本上,投object是合法的到任何你可以转换成object的东西。你不能投 object指针类型,例如,因为没有指针类型可以转换为 object .但其他一切都是公平的游戏。

通过转换为 object首先,您正在从编译器的权限范围内删除信息;你是说“忽略你知道这总是 C<bool> 用于错误检测的事实。

关于c# - 为什么 C# 编译器允许使用 Linq 而不是使用括号执行强制转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10048825/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com