C#类型转换不一致?

2024-01-21

在 C# 中,我无法隐式转换long to an int.

long l = 5;
int i = l;  // CS0266: Cannot implicitly convert type 'long' to 'int'. An explicit conversion exists (are you missing a cast?)

这会产生所述错误。确实如此;如果我这样做,我将面临由于错误截断而破坏数据的风险。如果我决定我知道我在做什么,那么我总是可以进行显式转换,并告诉编译器可以截断,我最了解。

int i = (int)l;  // OK

然而,当使用foreach loop.

IList<long> myList = new List<long>();
foreach (int i in myList)
{
}

编译器甚至不会在这里生成警告,尽管它本质上是同一件事:未经检查的截断long to an int,这很可能会破坏我的数据。

所以我的问题很简单:为什么会这样foreach不会产生与变量赋值相同的错误吗?


更新:这个问题是我2013年7月博客的主题 http://ericlippert.com/2013/07/22/why-does-a-foreach-loop-silently-insert-an-explicit-conversion/。感谢您提出的好问题!

为什么这个 foreach 不会产生与变量赋值相同的错误?

“为什么”问题很难回答,因为我不知道你问的“真正”问题。因此,我不会回答这个问题,而是回答一些不同的问题。

规范的哪一部分证明了这种行为的合理性?

正如 Michael Liu 的回答正确指出的那样,它是第 8.8.4 节。

整个点explicit转换是转换必须是explicit在代码中;这就是为什么我们有强制转换运算符;它挥舞着一面大旗,上面写着“这里有一个显式转换”。这是 C# 中代码中不存在显式转换的少数情况之一。哪些因素促使设计团队无形中插入“显式”转换?

The foreach循环是在泛型之前设计的。

ArrayList myList = new ArrayList();
myList.Add("abc");
myList.Add("def");
myList.Add("ghi");

你不想说:

foreach(object item in myList)
{
    string current = (string)item;

在没有仿制药的世界里,你必须提前知道列表中有哪些类型,以及你几乎总是具备这些知识。但该信息并未在类型系统中捕获。因此,你必须以某种方式告诉编译器,你可以通过说

foreach(string item in myList)

这是您对编译器的断言,即该列表充满字符串,就像强制转换是对特定项目是字符串的断言一样。

您完全正确,这在泛型世界中是一个错误特征。因为现在改变它会破坏它,所以我们坚持下去。

这个功能相当令人困惑;当我第一次开始 C# 编程时,我假设它具有如下语义:

while(enumerator.MoveNext())
{
    if (!(enumerator.Current is string) continue;
    string item = (string)enumerator.Current;

也就是说,“对于此列表中字符串类型的每个对象,执行以下操作”,而实际上是“对于此列表中的每个对象断言该项目是字符串并执行以下操作...”(如果前者是你真正想要什么然后使用OfType<T>()扩展方法。)

这个故事的寓意是:当你在版本 2 中大规模更改类型系统时,语言最终会出现奇怪的“遗留”功能。

在使用泛型的现代代码中,编译器是否应该针对这种情况发出警告?

我考虑过。我们的研究表明

foreach(Giraffe in listOfMammals)

is 如此常见大多数时候我们都会对正确的代码发出警告。这给每个打开“警告作为错误”进行编译的人带来了麻烦,而且一般来说,在代码上发出警告是很糟糕的,是的,可能有点臭,但是实际上是正确的。我们决定不再追究该警告。

是否存在 C# 编译器不可见地插入显式转换的其他情况?

是的。事实上,就在这件事发生几个小时后,就有人问了一个问题:

编译器将显式转换为我自己的类型替换为显式转换为 .NET 类型? https://stackoverflow.com/questions/16425856/compiler-replaces-explicit-cast-to-my-own-type-with-explicit-cast-to-net-type/16427263#16427263

在一些极其模糊的互操作场景中,也会插入显式转换。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C#类型转换不一致? 的相关文章

  • 删除文件的最后 10 个字符

    我想删除文件的最后 10 个字符 说一个字符串 hello i am a c learner 是文件内的数据 我只是希望该文件是 hello i am a 文件的最后 10 个字符 即字符串 c learner 应在文件内消除 解决方案 将
  • 通过引用传递 [C++]、[Qt]

    我写了这样的东西 class Storage public Storage QString key const int value const void add item QString int private QMap
  • 为什么 GCC 不允许我创建“内联静态 std::stringstream”?

    我将直接前往 MCVE include
  • 重载 (c)begin/(c)end

    我试图超载 c begin c end类的函数 以便能够调用 C 11 基于范围的 for 循环 它在大多数情况下都有效 但我无法理解和解决其中一个问题 for auto const point fProjectData gt getPoi
  • C# 列表通用扩展方法与非通用扩展方法

    这是一个简单的问题 我希望 集合类中有通用和非通用方法 例如List
  • 在 Unity 中实现 Fur with Shells 技术

    我正在尝试在 Unity 中实现皮毛贝壳技术 http developer download nvidia com SDK 10 5 direct3d Source Fur doc FurShellsAndFins pdf Fins 技术被
  • 如何获取 EF 中与组合(键/值)列表匹配的记录?

    我有一个数据库表 其中包含每个用户 年份组合的记录 如何使用 EF 和用户 ID 年份组合列表从数据库获取数据 组合示例 UserId Year 1 2015 1 2016 1 2018 12 2016 12 2019 3 2015 91
  • C# - 当代表执行异步任务时,我仍然需要 System.Threading 吗?

    由于我可以使用委托执行异步操作 我怀疑在我的应用程序中使用 System Threading 的机会很小 是否存在我无法避免 System Threading 的基本情况 只是我正处于学习阶段 例子 class Program public
  • C# 动态/expando 对象的深度/嵌套/递归合并

    我需要在 C 中 合并 2 个动态对象 我在 stackexchange 上找到的所有内容仅涵盖非递归合并 但我正在寻找能够进行递归或深度合并的东西 非常类似于jQuery 的 extend obj1 obj2 http api jquer
  • 为什么使用小于 32 位的整数?

    我总是喜欢使用最小尺寸的变量 这样效果就很好 但是如果我使用短字节整数而不是整数 并且内存是 32 位字可寻址 这真的会给我带来好处吗 编译器是否会做一些事情来增强内存使用 对于局部变量 它可能没有多大意义 但是在具有数千甚至数百万项的结构
  • 复制目录下所有文件

    如何将一个目录中的所有内容复制到另一个目录而不循环遍历每个文件 你不能 两者都不Directory http msdn microsoft com en us library system io directory aspx nor Dir
  • 有没有办法让 doxygen 自动处理未记录的 C 代码?

    通常它会忽略未记录的 C 文件 但我想测试 Callgraph 功能 例如 您知道在不更改 C 文件的情况下解决此问题的方法吗 设置变量EXTRACT ALL YES在你的 Doxyfile 中
  • 使用特定参数从 SQL 数据库填充组合框

    我在使用参数从 sql server 获取特定值时遇到问题 任何人都可以解释一下为什么它在 winfom 上工作但在 wpf 上不起作用以及我如何修复它 我的代码 private void UpdateItems COMBOBOX1 Ite
  • 对于某些 PDF 文件,LoadIFilter() 返回 -2147467259

    我正在尝试使用 Adob e IFilter 搜索 PDF 文件 我的代码是用 C 编写的 我使用 p invoke 来获取 IFilter 的实例 DllImport query dll SetLastError true CharSet
  • C++ 中的参考文献

    我偶尔会在 StackOverflow 上看到代码 询问一些涉及函数的重载歧义 例如 void foo int param 我的问题是 为什么会出现这种情况 或者更确切地说 你什么时候会有 对参考的参考 这与普通的旧参考有何不同 我从未在现
  • C# 使用“?” if else 语句设置值这叫什么

    嘿 我刚刚看到以下声明 return name null name NA 我只是想知道这在 NET 中叫什么 是吗 代表即然后执行此操作 这是一个俗称的 条件运算符 三元运算符 http en wikipedia org wiki Tern
  • DotNetZip:如何提取文件,但忽略zip文件中的路径?

    尝试将文件提取到给定文件夹 忽略 zip 文件中的路径 但似乎没有办法 考虑到其中实现的所有其他好东西 这似乎是一个相当基本的要求 我缺少什么 代码是 using Ionic Zip ZipFile zf Ionic Zip ZipFile
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲
  • 类型或命名空间“MyNamespace”不存在等

    我有通常的类型或命名空间名称不存在错误 除了我引用了程序集 using 语句没有显示为不正确 并且我引用的类是公共的 事实上 我在不同的解决方案中引用并使用相同的程序集来执行相同的操作 并且效果很好 顺便说一句 这是VS2010 有人有什么
  • 使用 WGL 创建现代 OpenGL 上下文?

    我正在尝试使用 Windows 函数创建 OpenGL 上下文 现代版本 基本上代码就是 创建窗口类 注册班级 创建一个窗口 choose PIXELFORMATDESCRIPTOR并设置它 创建旧版 OpenGL 上下文 使上下文成为当前

随机推荐