Почему свойства-коллекции C # не помечаются как устаревшие при вызове свойств для них?

Я попытался пометить свойство коллекции в классе как устаревшее, чтобы найти все события и сохранить сокращающийся список вещей, которые нужно исправить в моем списке предупреждений, из-за того, что нам нужно заменить это свойство коллекции чем-то другим.


Изменить: я отправил это через Microsoft Connect, проблема № 417159.

Редактировать 16.11.2010: проверено, что теперь это работает в компиляторе C # 4.0 как при компиляции для .NET 3.5, так и 4.0. Я получаю 4 предупреждения в опубликованном коде, в том числе с комментарием «Not OK?».


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

Вот пример программы, готовой к компиляции в Visual Studio 2008.

Обратите внимание на четыре строки рядом с концом, помеченные # 1- # 4, из них я ожидал, что все они сообщат, что используемое свойство устарело, а # 3 - нет, и кажется, что если я просто перейду непосредственно к свойствам или методам коллекции, использование самого свойства не помечается как устаревшее. Обратите внимание, что # 3 и # 4 ссылаются на одно и то же свойство, а # 4 помечено как использующее устаревшее свойство, а # 3 - нет. Тесты показывают, что если в выражении я обращаюсь к свойствам или методам коллекции, возвращаемой этим свойством, компилятор не жалуется.

Это ошибка или «скрытая жемчужина» компилятора C #, о которой я не знал?

using System;
using System.Collections.Generic;

namespace TestApp
{
    public abstract class BaseClass
    {
        [Obsolete]
        public abstract String Value
        {
            get;
        }

        [Obsolete]
        public abstract String[] ValueArray
        {
            get;
        }

        [Obsolete]
        public abstract List<String> ValueList
        {
            get;
        }
    }

    public class DerivedClass : BaseClass
    {
        [Obsolete]
        public override String Value
        {
            get
            {
                return "Test";
            }
        }

        [Obsolete]
        public override String[] ValueArray
        {
            get
            {
                return new[] { "A", "B" };
            }
        }

        [Obsolete]
        public override List<String> ValueList
        {
            get
            {
                return new List<String>(new[] { "A", "B" });
            }
        }
    }

    public class Program
    {
        public static void Main(String[] args)
        {
            BaseClass bc = new DerivedClass();
            Console.Out.WriteLine(bc.Value);             // #1 - OK
            Console.Out.WriteLine(bc.ValueArray.Length); // #2 - OK
            Console.Out.WriteLine(bc.ValueList.Count);   // #3 - Not OK?
            List<String> list = bc.ValueList;            // #4 - OK
        }
    }
}

person Lasse V. Karlsen    schedule 23.02.2009    source источник
comment
Я пометил ваше соединение как подтвержденное и поставил ему оценку ...   -  person Marc Gravell    schedule 23.02.2009
comment
кстати, я не ожидал исправления до C # 4.0; будет ли код компилироваться в 2.0? Возможно, попробуйте компилятор 2.0 ...   -  person Marc Gravell    schedule 23.02.2009
comment
нет, мы справимся, я обнаружил это случайно, когда пытался использовать ObsoleteAttribute как быстрый способ получить список задач, которые нужно исправить, прежде чем мы продолжим рефакторинг.   -  person Lasse V. Karlsen    schedule 23.02.2009


Ответы (3)


Хм ... мне кажется, это ошибка компилятора! Это не соответствует следующему (ECMA 334v4):

24.4.3 Атрибут Obsolete Атрибут Obsolete используется для обозначения типов и членов типов, которые больше не должны использоваться. Если программа использует тип или член, украшенный атрибутом Obsolete, то компилятор должен выдать предупреждение или ошибку, чтобы предупредить разработчика, чтобы можно было исправить ошибочный код. В частности, компилятор должен выдать предупреждение, если не указан параметр ошибки или если параметр ошибки предоставлен и имеет значение false. Компилятор должен выдать ошибку времени компиляции, если параметр ошибки указан и имеет значение true.

В частности, если он отмечен как истина, он должен выдать ошибку, а это не так. Хорошая находка! Вы можете сообщить об этом при «подключении», или, если вы не хотите мучиться с настройкой входа в систему, дайте мне знать, и я с радостью зарегистрирую его (ссылка на ваш пост здесь; никаких попыток «украсть» что-либо).

(Обновить)

Уменьшенный код для воспроизведения:

using System;
using System.Collections.Generic;
static class Program {
    static void Main() {
        int count = Test.Count;
    }

    [Obsolete("Should error", true)]
    public static List<string> Test {
        get {throw new NotImplementedException();}
    }
}

Обратите внимание, что mono 2.0 делает это правильно, как и компилятор MS C # 2.0. Неисправен только компилятор MS C # 3.0 (.NET 3.5).

person Marc Gravell    schedule 23.02.2009
comment
Хорошо, это подтверждает мои подозрения, я отредактировал свой вопрос и разместил ссылку на проблему с подключением. - person Lasse V. Karlsen; 23.02.2009

Это настоящая ошибка. К сожалению, из-за очистки кода при рефакторинге этот случай был упущен. Я исправил это в выпуске компилятора C # 4.0, который появится в VS 2010 / NDP 4.0, но сейчас нет планов исправлять это в Orcas, и, к сожалению, я не знаю, как с этим справиться.

Ненавижу это говорить, но вам нужно будет перейти на NDP 4 csc.exe или VS2010, когда они станут доступны, чтобы решить эту проблему.

Я подумываю опубликовать об этом запись в моем новом блоге msdn. Это хороший анекдотический пример того, как рефакторинг может сломать ваш код.

Иэн Холлидей

SDE компилятора C #
Microsoft

person Ian Halliday    schedule 17.03.2009
comment
Спасибо, что нашли время опубликовать это здесь. Оценил. - person Marc Gravell; 17.03.2009
comment
Да, в самом деле. Думаю, еще одна веха для Stack Overflow :) - person Jon Skeet; 17.03.2009

Я согласен с Марком: это похоже на ошибку компилятора. Интересно, что gmcs (компилятор Mono C #) понимает это правильно:

Test.cs(65,26): warning CS0219: The variable `list' is assigned but its value is never used
Test.cs(62,38): warning CS0612: `TestApp.BaseClass.Value' is obsolete
Test.cs(63,38): warning CS0612: `TestApp.BaseClass.ValueArray' is obsolete
Test.cs(64,38): warning CS0612: `TestApp.BaseClass.ValueList' is obsolete
Test.cs(65,36): warning CS0612: `TestApp.BaseClass.ValueList' is obsolete
Compilation succeeded - 5 warning(s)
person Jon Skeet    schedule 23.02.2009
comment
Могу принять только одного, поэтому я принимаю Марка таким, каким он был первым :) - person Lasse V. Karlsen; 23.02.2009