Re: [Этюд, C#] Cast expression
От: Пельмешко Россия blog
Дата: 12.04.11 21:45
Оценка: 176 (9)
Здравствуйте, nikov, Вы писали:
N>
N>class C
N>{
N>    unsafe static void Main()
N>    {
N>        var x = (global::C) -1;
N>        var y = (global::System.Int32) -1;
N>        var z = (global::System.Int32*) -1;
N>    }
    
N>    public static implicit operator C(int x) { return null; }
N>}


N>Скомпилируется ли эта программа? Если нет, то какие будут ошибки?


Не скомпилируется, отвалится строка (шок):

var y = (global::System.Int32) -1;

Смотрим правила разрешения неоднозначностей в cast expressions:

To resolve cast-expression ambiguities, the following rule exists: A sequence of one or more tokens (§2.3.3) enclosed in parentheses is considered the start of a cast-expression only if at least one of the following are true:

• The sequence of tokens is correct grammar for a type, but not for an expression.
• The sequence of tokens is correct grammar for a type, and the token immediately following the closing parentheses is the token “~”, the token “!”, the token “(”, an identifier (§2.4.1), a literal (§2.4.4), or any keyword (§2.4.3) except as and is.

Так вот, последовательность токенов global::System.Int32 является корректной с точки зрения грамматики, но при этом может означать и тип, и выражение (например, статическое поле Int32 класса System). Второе правило тоже не катит, так как после закрывающей скобки не идут токены “~”, “!”, “(” либо идентификаторы, литералы или ключевые слова (кроме as и is). Стоп! -1 разве не литерал? Оказывается, что с точки зрения C# — нет, это не literal expression, это унарное выражение отрицания литерала 1!

В итоге C# не будет считать выражение приведением типов и будет ругаться на непонятное использование имени типа lobal::System.Int32 в выражении.

var z = (global::System.Int32*) -1;

Тут срабатывает первое правило — последовательность токенов global::System.Int32* корректна и в C# может означать только тип, не выражение (так как global::System.Int32* — это и не умножение, и не pointer inderection (префиксная унарная операция)). И абсолютно не важно что там после закрывающей скобки.

var x = (global::C) -1;

Тут тоже первое правило — последовательность токенов global::C может являться корректной записью типа, но не выражения ("внутри" пространства имён global, как и любого другого, не могут содержаться значения).

 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.