为什么CS0246是;类型或命名空间名称';名称';“找不到”;C#错误如此混乱?

为什么CS0246是;类型或命名空间名称';名称';“找不到”;C#错误如此混乱?,c#,.net,using,C#,.net,Using,下面是一个场景。我在VisualStudio中创建了一个新的类库项目,添加了一些类。然后在某个时刻,我决定需要使用System.Runtime.Serialization.DataContractAttribute标记某个类,并编写以下代码: [DataContract] public class MyDataContractClass {} 当我点击compile时,我看到以下错误: 错误CS0246:找不到类型或命名空间名称“DataMember”(是否缺少using指令或程序集引用?)

下面是一个场景。我在VisualStudio中创建了一个新的类库项目,添加了一些类。然后在某个时刻,我决定需要使用
System.Runtime.Serialization.DataContractAttribute
标记某个类,并编写以下代码:

[DataContract]
public class MyDataContractClass {}
当我点击compile时,我看到以下错误:

错误CS0246:找不到类型或命名空间名称“DataMember”(是否缺少using指令或程序集引用?)

好的,问题是我忘了使用指令添加
,以使类可见。我补充说

using System.Runtime.Serialization;
指向类上方的同一个文件,但问题不会消失,直到我在项目资源管理器中添加对
System.Runtime.Serialization
的引用

这很令人困惑。为什么我必须在不同的地方添加相同的内容两次,并且无论我错过了两个步骤中的哪一个,都会看到相同的错误消息


我的问题如下。这仅仅是设计糟糕的错误诊断还是有一些根本原因为什么上面两个步骤中的任何一个缺失都会导致C#编译器发出相同的错误?

您会收到相同的错误消息,因为就编译器而言,这是一个相同的问题:它找不到您要使用的类型指。如果不知道您试图引用的是哪种类型,它就不知道您是否缺少使用
指令的
或引用-这是一种第22条军规的情况

您认为编译器应该如何知道是因为缺少使用
指令的
,还是因为缺少引用而找不到类型?它是否应该检查每个引用中每个名称空间中的每个类型,让您知道您缺少使用
指令的
?这仍然可能是错误的,因为您可能实际上是指一个完全不同的类型,在不同的命名空间中。(事实上,像Intellisense和ReSharper这样的东西都愿意为您提供选项——编译器不能真正做到这一点。)

现在假设您知道您指的是哪种类型,问题很容易解决,因为您可以检查两个方面:

  • 确保您已获得对相应程序集的引用
  • 确保您已使用
指令获得适当的


你已经掌握了找出问题所在所需的所有信息。编译器没有


当然,如果您也不知道您指的是哪种类型,那么期望编译器这样做是非常不合理的。

事实上,我认为错误消息非常描述了问题和解决方案。警告状态为
是否缺少using指令或程序集引用?
,并且确实缺少这两个指令

至于为什么这不是两个独立的警告,当然,编译器可以通过该名称查看是否存在可访问的类型,并使用
发出警告,但如果没有,则发出警告。但为什么要这样做呢?
这会很慢,而且它几乎不会在表上显示额外的信息,因为程序员通常比编译器更清楚他/她正在尝试做什么


为了避免这个问题,ReSharper有一个很好的功能,可以在需要时自动添加引用。

你不会重复同样的操作。任何程序集都可以在任何命名空间中包含类型。使用语句的
只是引用命名空间中类型的快捷方式,而这些类型可以由任何程序集提供

系统提供的程序集中的一般约定是,与名称空间同名的程序集将在该名称空间中包含大量类型-但如果编译器无法解析类型名,编译器无法知道您忘记引用了哪个程序集-它甚至无法知道(直到您添加正确的程序集)该DataContract位于
System.Runtime.Serialization
命名空间中


要让它根据您的需要改进诊断,它需要在编译时:

  • 了解上次编译尝试期间发出的错误消息
  • 了解已更改的源文件的以前状态和当前状态
  • 假设中间添加的任何文本都是您试图解决任何/所有以前的错误
  • 然后更改它的搜索策略,以便它只在新using语句中搜索以前未解析的类型名

因此,实际上有三个错误选项,1-缺少使用,2-缺少引用,3-PEBKAC问题:)我认为这是OP的关键信息:与Java世界不同,在.NET中,类型的名称空间和类型的程序集名称与框架无关。它只是一种广泛使用的约定,使名称空间和程序集名称相似。@Michael:Java实际上没有程序集的概念,但需要两个相同的步骤:在类路径中放置库,添加导入语句。@Jon:我的观点是Java需要在某个容器中查找类,名称空间是其中的一个重要部分。在.NET中,命名空间实际上与框架查找类型的位置无关。您可能会惊讶于我花了多长时间才发现我的Java类必须位于类路径目录下的特定文件系统路径中。我并不是说Java中的“步骤”更少,而是
import
会影响Java如何查找类,而.NET中使用
语句的
则不会影响类的查找。@Michael:不,Java中的名称空间不是“容器”中包含类文件的重要部分。它是Java如何在容器中查找类的重要部分,而不是它使用的容器。因此foo.bar.Baz的类可以在foo.jar或xyz.j中