Защо този код се компилира без грешка, въпреки че класът е маркиран като остарял?

Това е Visual Studio 2008. Очевидно е свързано със статичния клас за разширения.

public class Dummy
{
    public readonly int x;

    public Dummy(int x)
    {
        this.x = x;
    }

    public override string ToString()
    {
        return x.ToString();
    }
}

[Obsolete("Do Not Use", true)]
public static class Extensions
{
    public static int Squared(this Dummy Dummy)
    {
        return Dummy.x * Dummy.x;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var d = new Dummy(42);
        Console.WriteLine(String.Format("{0}^2={1}", d, d.Squared()));
    }
}

person Cade Roux    schedule 10.05.2011    source източник


Отговори (5)


Това репродукции и във VS2010. Прилича на бъг. Ще го вкарам в базата данни.

Можете да заобиколите грешката, като поставите атрибута на действителния метод.

Благодаря за доклада!

person Eric Lippert    schedule 10.05.2011

Извикването на остаряла функция е предупреждение, а не грешка, освен ако не промените настройките на компилатора, за да спрете и при предупреждения - за да накарате предупрежденията да се държат като грешки.

Обикновено не виждам тези предупреждения, освен ако няма други „истински“ грешки в моя код.

Също така забележете, че във вашия конкретен случай сте маркирали класа като остарял - не метода. Това може да има значение.

person n8wrl    schedule 10.05.2011
comment
Вторият параметър на атрибута Obsolete показва дали това трябва да е грешка или не. - person Ryan Emerle; 11.05.2011

Мисля, че сте открили бъг в компилатора:

Въпреки че методът на разширението ще бъде компилиран за използване на статичен метод, изглежда, че компилаторът не го проверява, тъй като по време на компилирането той съществува във формата на извикване на метод на екземпляр.


Причината е тук. Ако декларирам втори метод:

[Obsolete("Do Not Use", true)]
public static class Extensions
{
    public static int Squared(this Dummy Dummy)
    {
        return Dummy.x * Dummy.x;
    }

    public static int Squared2(Dummy Dummy)
    {
        return Dummy.x * Dummy.x;
    }

}

Сега се оплаква на 3-ти ред, а не на второ:

class Program
{
    static void Main(string[] args)
    {
        var d = new Dummy(42);
        Console.WriteLine(String.Format("{0}^2={1}", d, d.Squared())); // Fine!?
        Console.WriteLine(String.Format("{0}^2={1}", d, Extensions.Squared2(d))); // COmplains as expected
    }
}
person Aliostad    schedule 10.05.2011

Тъй като това е метод на разширение, вие нямате директен достъп до статичния клас, компилаторът генерира този код.

Ако вместо това сте осъществили достъп до метода Squared изрично, ще получите грешката по време на компилиране.

Extensions.Squared(d)

Тъй като обаче това е метод за разширение, вие само косвено извиквате метода, така че атрибутът ще трябва да се приложи към самия метод.

public static class Extensions
{
    [Obsolete("Do Not Use", true)]
    public static int Squared(this Dummy Dummy)
    {
        return Dummy.x * Dummy.x;
    }
}

От друга страна, изтриването (или преименуването) на класа като цяло би послужило за същата цел - определено ще получите грешка по време на компилиране в този случай. :)

РЕДАКТИРАНЕ
Можете да подадете сигнал за грешка в Microsoft тук. Това изглежда като поведение, което трябва да се обработва от компилатора.

person Ryan Emerle    schedule 10.05.2011
comment
Това не означава, че не би било хубаво, ако компилаторът поддържа атрибута Obsolete на статични класове за методи за разширение. - person Ryan Emerle; 11.05.2011
comment
Това е някак страшно, защото може да приемете, че нещо, маркирано като остаряло/вярно, може да бъде премахнато (други остарели/истински неща, които са в неизползвани кодови пътеки, също може да се наложи да бъдат премахнати и предполагам, че това може да се счита за фин вариант на това) . - person Cade Roux; 11.05.2011
comment
Със сигурност можете да имате нестатичен клас, маркиран като остарял/истински, който има други остарели/истински неща в зависимост от него и той ще се компилира без грешка, докато цялата тази част от обектния модел е осиротяла. - person Cade Roux; 11.05.2011

Мисля, че трябва да поставите атрибута на Squared, а не на класа.

person Lou Franco    schedule 10.05.2011
comment
Не. Срещу него е дефинирано AttributeUsage.Class. - person Aliostad; 11.05.2011
comment
При нестатичните класове даден клас може да бъде маркиран като остарял, без да се налага да се маркира нещо друго като остаряло. Разбирам, че статичен клас изобщо не е като нестатичен клас, но изглеждаше странно, че не даде никакво предупреждение, че атрибутът е невалиден на това ниво. - person Cade Roux; 11.05.2011
comment
Валидно е със статичен клас, поставете всяка функция без разширение там и опитайте да я извикате и тя ще изведе грешка. Функцията за разширение просто убягва от вниманието на атрибута на статичния клас, защото всъщност не е част от класа Extensions, а част от класа Dummy. - person Felan; 11.05.2011
comment
@Felan, В отговора на Ryan и примера на Aliostad изглежда, че понякога може да се счита за част от този остарял клас, ако е достъпен изрично. Така че това е вид шизоид. - person Cade Roux; 11.05.2011