Статические классы С# и оператор-оператор

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

Эта полная программа показывает ситуацию:

static class ExtensionMethods {}

class Program {

    static void Main() {
        Test("Test");
    }

    public static bool Test(object obj)
    {
        return obj is ExtensionMethods;
    }
}

Я бы предположил, что "obj is ExtensionMethods" вызывает какое-то предупреждение, учитывая, что ExtensionMethods является статическим классом.

Компилятор выдаст предупреждение для оператора "is", если объект, находящийся в процессе тестирования, никогда не может быть предоставленного типа, например ((string)obj) is System.Uri.

Я забыл сценарий, в котором это будет действительно значимым тестом?

Ответы

Ответ 1

Я был очень удивлен, что это не ошибка компилятора или предупреждение.

Это должно было быть. Это был недосмотр.

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

По-видимому, этот, который я видел раньше, никогда не фиксировался. Извинения за надзор.

Я забыл сценарий, в котором это будет действительно значимым тестом?

Нет.

Ответ 2

Из спецификации С# 3.0, раздел 10.1.1.3:

Статический класс не может включать спецификацию класса (§10.1.4) и не может явно указывать базовый класс или список реализованных интерфейсов. Статический класс неявно наследуется от объекта типа.

Поэтому компилятор, по-видимому, не вызывает предупреждения, потому что он не знает, что is всегда будет возвращать false. (Статический класс "есть" object, и поэтому компилятор не знает, что object "is" или "is" не является статическим классом во время компиляции.) Реально он, вероятно, знает или, по крайней мере, может узнайте, но, по-видимому, он не специализируется на этом случае и проверке.

Ответ 3

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

Например, если вы сделаете следующее, вы получите следующую ошибку: "Невозможно объявить переменную статического типа"

ExtensionMethods ex;

Если вы выполните ниже, вы получите следующую ошибку: "Невозможно создать экземпляр статического класса"

ExtensionMethods ex2 = new ExtensionMethods();

Чтобы продемонстрировать эту проблему, вот полная программа, показывающая, что оператор is.

static class ExtensionMethods { }

// notice non-static
class AnotherNonStaticExtensionMethod { }

class Program
{
    static void Main(string[] args)
    {
        Debug.WriteLine(Test(new AnotherNonStaticExtensionMethod()).ToString());
        Debug.WriteLine(Test("Test").ToString());
        Debug.WriteLine(Test(4).ToString());
    }

    public static bool Test(object obj)
    {
        if (obj is ExtensionMethods)
        {
            return true;
        }
        else if (obj is AnotherNonStaticExtensionMethod)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

Вот следующий вывод:

True
False
False

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

Предоставлено NominSim::

Из спецификации С# 3.0, раздел 10.1.1.3:

Статический класс не может включать спецификацию класса (§10.1.4) и не может явно указывать базовый класс или список реализованных интерфейсы. Статический класс неявно наследует от объекта типа.

Ответ 4

Ответ Эрика Липперта с 2013 года объясняет, что это было ошибкой в ​​компиляторе Visual С# 5.0 (и некоторых более ранних версиях). Проблема была и с оператором as, например object bad = obj as ExtensionMethods;.

В С# 6.0 (с 2015 года) и позже вы получаете ошибку времени компиляции (а не только предупреждение):

ошибка CS7023: второй операнд оператора 'is' или 'as' может не быть статическим типом "Xxxx"

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

Ответ 5

В соответствии с Спецификацией языка С#:

Оператор is используется для динамической проверки, совместим ли тип времени выполнения с данным типом. Результатом операции E является T, где E является выражением, а T является типом, является логическим значением, указывающим, может ли E быть успешно преобразован в тип T посредством эталонного преобразования, преобразования бокса или преобразования для распаковки.

и

Статический класс не может включать спецификацию класса (§10.1.4) и не может явно указывать базовый класс или список реализованных интерфейсов. Статический класс неявно наследует от объекта типа.

Поскольку он наследует от System.Object неявно, имеет смысл, что компилятор не выдает предупреждение.

Проверка:

var staticBaseType = typeof(B).BaseType;

В качестве базового типа вы получите System.Object.