C#类型转换不一致?

编程入门 行业动态 更新时间:2024-10-28 22:25:55
本文介绍了C#类型转换不一致?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

在C#中,我不能隐式地将 long 转换为 int 。

long l = 5; int i = l; // CS0266:不能将类型'long'隐式转换为'int'。显式转换存在(是否缺少转换?)

这会产生所述错误。正确地如果我这样做,我有可能打破我的数据,由于错误的截断。如果我决定我知道我在做什么,那么我总是可以做一个明确的演员,并告诉编译器,这是可以截断,我知道最好。

int i =(int)l; // OK

但是,使用 foreach 循环。

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

编译器甚至不会在这里生成警告,即使它本质上是相同的事情: long 到 int ,这可能会打破我的数据。

所以我的问题是:为什么 foreach

解决方案

更新:这个问题是 2013年7月我的博客主题。非常感谢您的问题!

为什么foreach不会创建与变量赋值相同的错误?

为什么问题很难回答,因为我不知道你问的真正的问题。

该规范的哪一部分证明了这种行为?

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

显式转换的整个要点是转换必须在代码中显式; 这就是为什么我们有cast操作符;它挥舞着一个大旗,说这里有一个明确的转换。这是C#中的少数几次之一,其中显式转换不在代码中。什么因素促使设计团队无形地插入显式转换?

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

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

您不想说:

foreach(myList中的对象项) { string current =(string)item;

在没有泛型的世界里,你必须提前知道什么类型都在列表中,并且您几乎总是拥有该知识。但是这种信息不会在类型系统中捕获。因此,你必须告诉编译器某种方式,你这样说:

foreach(myList中的字符串项)

这是你对编译器的断言,即列表中有很多字符串,就像一个转换是一个断言,特定的项目是一个字符串。

你是完全正确的,这是一个错误的特征在一个世界上的泛型。

这个功能很混乱;当我第一次开始编程C#我假设它有语义的东西像:

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

也就是说,对于此列表中每个类型为字符串的对象,执行以下操作,当它真的是时,对于此列表中的每个对象,断言该项是一个字符串并执行以下操作...(如果前者是您实际需要的,那么使用 OfType< T>()扩展方法。)

当你大幅更改版本2中的类型系统时,故事的道德是:语言最终会出现奇怪的遗产功能。

如果编译器在现代代码中为这种情况产生一个警告,在哪里使用泛型?

我们的研究表明,

foreach(listOfMammals中的Giraffe) pre>

是常见的,大多数时候我们会给出正确代码的警告。这对每个编译警告作为错误的人都带来麻烦,一般来说,对代码的警告是肯定的,但可能有点臭,但实际上是正确的。

有没有其他情况下,C#编译器不可见地插入显式转换?

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

>

有一些非常模糊的互操作场景,也会插入显式转换。

In C#, I cannot implicitly convert a 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?)

This produces said error. And rightly so; if I do that, I am at risk of breaking my data, due to erroneous truncation. If I decide that I know what I am doing, then I can always do an explicit cast, and tell the compiler that it's okay to truncate, I know best.

int i = (int)l; // OK

However, the same mechanism does not seem to apply when using a foreach loop.

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

The compiler does not even generate a warning here, even though it is essentially the same thing: an unchecked truncation of a long to an int, which might very well break my data.

So my question is simply: Why does this foreach not create the same error as the variable assignment does?

解决方案

UPDATE: This question was the subject of my blog in July of 2013. Thanks for the great question!

Why does this foreach not create the same error as the variable assignment does?

"Why" questions are difficult to answer because I don't know the "real" question you're asking. So instead of answering that question I'll answer some different questions.

What section of the specification justifies this behaviour?

As Michael Liu's answer correctly points out, it is section 8.8.4.

The whole point of an explicit conversion is that the conversion must be explicit in the code; that's why we have the cast operator; it's waving a big flag that says "there's an explicit conversion right here". This is one of the few times in C# where an explicit conversion is not extant in the code. What factors motivated the design team to invisibly insert an "explicit" conversion?

The foreach loop was designed before generics.

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

You don't want to have to say:

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

In a world without generics you have to know ahead of time what types are in a list, and you almost always do have that knowledge. But this information is not captured in the type system. Therefore, you have to tell the compiler somehow, and you do that by saying

foreach(string item in myList)

This is your assertion to the compiler that the list is full of strings, just like a cast is an assertion that a particular item is a string.

You are completely correct that this is a misfeature in a world with generics. Since it would be breaking to change it now, we're stuck with it.

The feature is quite confusing; when I first started programming C# I assumed that it had the semantics of something like:

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

That is, "for each object of type string in this list, do the following", when it really is "for each object in this list assert that the item is a string and do the following..." (If the former is what you actually want then use the OfType<T>() extension method.)

The moral of the story is: languages end up with weird "legacy" features when you massively change the type system in version 2.

Should the compiler produce a warning for this case in modern code, where generics are being used?

I considered it. Our research showed that

foreach(Giraffe in listOfMammals)

is so common that most of the time we'd be giving a warning for correct code. That creates trouble for everyone who compiles with "warnings as errors" turned on, and it's generally speaking badness to have a warning on code that is yes maybe a bit smelly but actually correct. We decided to not pursue the warning.

Are there other situations where the C# compiler invisibly inserts explicit conversions?

Yes. In fact someone asked a question about that just a few hours after this one:

Compiler replaces explicit cast to my own type with explicit cast to .NET type?

There are some extremely obscure interop scenarios where explicit conversions are inserted as well.

更多推荐

C#类型转换不一致?

本文发布于:2023-10-19 14:19:09,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1507782.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:类型

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!