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

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


Изменить. Я отправил это через Microsoft Connect, issue # 417159.

Изменить 16.11.2010: проверено, что это теперь работает в компиляторе С# 4.0, как при компиляции для .NET 3.5, так и 4.0. Я получаю 4 предупреждения в опубликованном коде, в том числе с комментарием "Не в порядке?".


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

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

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

Является ли это ошибкой, или это "скрытый камень" компилятора С#, о котором я не знал?

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
        }
    }
}

Ответы

Ответ 1

Хм... выглядит как ошибка компилятора для меня! Он не выполняет следующие действия (ECMA 334v4):

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

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

(обновление)

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

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 С# 2.0. Это нарушает только компилятор MS С# 3.0 (.NET 3.5).

Ответ 2

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

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

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

Ян Холлидей

Компилятор С# SDE
Microsoft

Ответ 3

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

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)