Почему CS0246 «Тип или имя пространства имен« Имя »не могут быть найдены» ошибка C # так сбивает с толку? - PullRequest
0 голосов
/ 22 марта 2011

Вот сценарий. Я создаю новый проект библиотеки классов в Visual Studio, добавляю несколько классов. Затем в какой-то момент я решаю, что мне нужно пометить некоторый класс System.Runtime.Serialization.DataContractAttribute, и я пишу следующее:

[DataContract]
public class MyDataContractClass {}

и когда я нажимаю на compile, я вижу следующую ошибку:

ошибка CS0246: не удалось найти тип или имя пространства имен 'DataMember' (отсутствует директива using или ссылка на сборку?)

Хорошо, проблема в том, что я забыл добавить директиву using, чтобы сделать класс видимым. Я добавляю

using System.Runtime.Serialization;

к тому же файлу над классом, но проблема не исчезнет, ​​пока я не добавлю ссылку на System.Runtime.Serialization в Project Explorer.

Это очень запутанно. Почему я должен добавить одну и ту же вещь два раза в разных местах и ​​ увидеть одно и то же сообщение об ошибке независимо от того, какой из двух шагов я пропустил ?

У меня следующий вопрос. Это просто плохо спроектированная диагностика ошибок или есть какая-то фундаментальная причина , почему пропуск любого из двух вышеуказанных шагов приводит к той же ошибке испускается компилятором C #?

Ответы [ 3 ]

5 голосов
/ 22 марта 2011

Вы не делаете одно и то же дважды.Любая сборка может содержать типы в любом пространстве имен.Оператор using - это всего лишь ярлык для ссылки на типы в пространстве имен - и эти типы могут предоставляться любой сборкой.

Общее соглашение в поставляемых системой сборках заключается в том, что сборки с тем же именем, что и пространство имен, будутсодержит большое количество типов в этом пространстве имен - но у компилятора нет возможности узнать, на какую сборку вы забыли сослаться, если он не может разрешить имя типа - он даже не может знать (пока вы не добавите нужную сборку) что DataContract находится в пространстве имен System.Runtime.Serialization.


Чтобы улучшить диагностику, как вам нужно, при компиляции необходимо:

  • знать ошибкусообщения, которые были отправлены во время предыдущей попытки компиляции
  • , знают предыдущее состояние и текущее состояние исходных файлов, которые изменились
  • предполагают, что любой текст, добавленный между ними, был вашимпопытаться устранить любые / все предыдущие ошибки
  • , а затем изменить стратегию поиска, чтобы онаy ищет ранее неразрешенные имена типов в новых операторах using.
5 голосов
/ 22 марта 2011

Вы получаете то же сообщение об ошибке, потому что для компилятора это та же проблема: он не может найти тип, на который вы ссылаетесь. Не зная, к какому типу вы пытаетесь обратиться, он не знает, пропустили ли вы директиву using или ссылку - это ситуация с уловкой-22.

Как, по вашему мнению, компилятор должен знать, не может ли он найти тип, потому что вы пропустили директиву using или потому что пропустили ссылку? Должен ли он просматривать каждый тип в каждом пространстве имен в каждой ссылке, чтобы вы знали, что у вас отсутствует директива using? Это все еще может быть неверно, потому что вы можете иметь в виду совершенно другой тип в другом пространстве имен. (На самом деле, такие вещи, как Intellisense и ReSharper готовы предложить вам варианты - компилятор не может этого сделать).

Теперь, предполагая, вы знаете, какой тип вы имеете в виду, проблему легко решить, потому что вы можете проверить оба аспекта:

  • Убедитесь, что у вас есть ссылка на соответствующую сборку
  • Убедитесь, что у вас есть соответствующая директива using

У вас есть вся необходимая информация, чтобы выяснить, в чем дело. Компилятор не имеет.

Конечно, если вы тоже не знаете, какой тип вы имеете в виду, то ожидать компилятора от этого довольно неразумно.

2 голосов
/ 22 марта 2011

На самом деле, я думаю, что сообщение об ошибке было довольно описательным как для проблемы, так и для ее решения. Предупреждение гласит are you missing a using directive or an assembly reference?, и вы действительно упустили оба.

Что касается того, почему это не два отдельных предупреждения, конечно, компилятор мог видеть, существует ли достижимый тип с этим именем, и выдавать using предупреждение, если оно есть, но выдавать предупреждение reference, если есть нет. но зачем это?
Это будет медленно и почти никогда не принесет дополнительную информацию в таблицу, поскольку программист обычно лучше знает, что он / она пытается сделать, чем компилятор.

Чтобы обойти проблему, ReSharper имеет замечательную функцию, которая автоматически добавит ссылку, если и где это необходимо.

...