Why do I NOT get warnings about uninitialized readonly fields?(为什么我没有收到有关未初始化的只读字段的警告?)
问题描述
如果您忘记初始化私有或内部的只读成员,或者声明它的类是内部的,C# 编译器会很友好地给您一个字段从未分配给"警告.但是如果类是公共的,而只读成员是公共的、受保护的或受保护的内部的,那么就不会给你任何警告!
The C# compiler is kind enough to give you a "field is never assigned to" warning if you forget to initialize a readonly member which is private or internal, or if the class in which it is being declared is internal. But if the class is public, and the readonly member is public, protected or protected internal, then no warning for you!
有人知道为什么吗?
演示发出警告的条件和不发出警告的条件的示例代码:
Sample code which demonstrates the conditions under which the warning is issued, and the conditions under which the warning is not issued:
namespace Test1
{
class Test1
{
#if TRY_IT
public readonly int m; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0
protected readonly int n; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0
internal readonly int o; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0
private readonly int p; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0
protected internal readonly int q; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0
Test1()
{
if( p != 0 ) //To avoid warning 'The field is never used'
return;
}
#endif
}
public class Test2
{
#if TRY_IT
private readonly int m; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0
internal readonly int n; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0
Test2()
{
if( m != 0 ) //To avoid warning 'The field is never used'
return;
}
#endif
public readonly int o; //Blooper: no warning about field never assigned to.
protected readonly int p; //Blooper: no warning about field never assigned to.
protected internal readonly int q; //Blooper: no warning about field never assigned to.
}
public sealed class Test3
{
public readonly int m; //Blooper: no warning about field never assigned to.
}
}
有那么一刻,您可能会认为编译器不会在公共和受保护成员的情况下发出警告,因为可以合理地预期派生类可能会初始化该字段.这个理论站不住脚,原因有很多:
For a moment you might think that the compiler refrains from issuing the warning in the case of public and protected members because it is reasonable to expect that derived classes might initialize the field. This theory does not hold any water for a number of reasons:
一个内部类可以被子类化,但编译器不会在这种情况下不要发出警告.
An internal class may be subclassed, but the compiler does not refrain from issuing the warning in that case.
即使在密封的情况下编译器也无法发出警告类,如示例代码中的 Test3 所示.
The compiler fails to issue the warning even in the case of a sealed class, as Test3 in the sample code demonstrates.
为了基地的完整性,警告是有意义的无论派生类可以做什么或不可以做什么.
The warning makes sense for the sake of the integrity of the base class regardless of what a derived class may or may not do.
语言明确禁止类初始化基类的只读成员.(谢谢,吉姆·米歇尔.)
A class is expressly prohibited by the language from initializing a readonly member of a base class. (Thanks, Jim Mischel.)
如果我没记错的话,Java 在所有情况下都会给出所有正确的警告,无论未初始化的 final 成员是公共的、受保护的还是私有的,也不管类是否包含它是公开的或仅在其包中可见.
If my memory serves me well, Java gives all the proper warnings in all cases, regardless of whether the uninitialized final member is public, protected or private, and regardless of whether the class containing it is public or visible only within its package.
推荐答案
简短的回答:这是编译器的疏忽.
The short answer: this is an oversight in the compiler.
更长的答案:确定要为已声明但从未使用过、写入但从未阅读过、或已阅读但从未写入过的成员和本地人发出什么警告的启发式方法不采用该字段的只读性考虑到.正如您正确指出的那样,它可能会在更多情况下发出警告.例如,我们可以说未在任何 ctor 中初始化的公共只读字段将始终具有其默认值".
The longer answer: the heuristic which determines what warnings to issue for members and locals that are declared and never used, or written and never read, or read and never written, does not take the read-only-ness of the field into consideration. As you correctly note, it could, and thereby issue warnings in more cases. We could say that a public readonly field that is not initialized in any ctor "will always have its default value" for example.
我会在新的一年里向 Neal 提到它,我们会看看我们是否可以改进 Roslyn 的启发式方法.
I'll mention it to Neal in the new year and we'll see if we can improve those heuristics in Roslyn.
顺便说一句,在许多情况下可能会发出此类警告(无论是否只读),但我们不会这样做.我今天不在办公室,所以我手边没有列出所有这些情况的清单,但我只想说有很多.就像该字段被声明为公共的并且在内部类的公共嵌套类中"之类的东西.在这种情况下,该字段实际上是内部的,我们可以发出警告,但有时我们不会.
Incidentally, there are a number of situations in which a warning of this sort could be issued (regardless of read-only-ness) but we do not do so. I am not in my office today so I don't have my list of all those situations handy, but suffice to say there are a lot of them. It was stuff like "the field is declared as public and is in a public nested class of an internal class". In that situation the field is effectively internal and we can do the warning, but sometimes we do not.
多年前的一天,我更改了启发式方法,以便 每个 可以静态知道未使用的字段产生警告,并且当该更改进入 C# 编译器的内部版本时我们用来编译用 C# 编写的类库,一切都乱套了.那些家伙总是在打开错误警告"的情况下进行编译,突然间他们开始收到关于故意初始化或仅通过反射和其他动态技术使用的各种字段的警告.我在很大程度上破坏了构建.现在,有人可能会争辩说,嘿,这些人应该修复他们的代码,以便它抑制警告(我确实如此争论)但最终结果证明将警告启发式恢复到以前的水平更容易.我应该更缓慢地进行更改.
One day many years ago I changed the heuristic so that every field that could be statically known to be unused produced a warning, and when that change made it into the internal version of the C# compiler that we use to compile the class libraries that are written in C#, all hell broke loose. Those guys always compile with "warnings as errors" turned on, and suddenly they started getting warnings on all kinds of fields that were deliberately initialized or used onl via reflection, and other dynamic techniques. I broke the build in a major way. Now, one might argue that hey, these guys should fix their code so that it suppresses the warning (and I did argue that) but ultimately it turned out to be easier to back the warning heuristic off to its previous level. I should have made the change more gradually.
这篇关于为什么我没有收到有关未初始化的只读字段的警告?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:为什么我没有收到有关未初始化的只读字段的警告?
基础教程推荐
- 将 XML 转换为通用列表 2022-01-01
- 有没有办法忽略 2GB 文件上传的 maxRequestLength 限制? 2022-01-01
- SSE 浮点算术是否可重现? 2022-01-01
- rabbitmq 的 REST API 2022-01-01
- 将 Office 安装到 Windows 容器 (servercore:ltsc2019) 失败,错误代码为 17002 2022-01-01
- c# Math.Sqrt 实现 2022-01-01
- 如何在 IDE 中获取 Xamarin Studio C# 输出? 2022-01-01
- MS Visual Studio .NET 的替代品 2022-01-01
- 为什么Flurl.Http DownloadFileAsync/Http客户端GetAsync需要 2022-09-30
- 如何激活MC67中的红灯 2022-01-01