Re[2]: поведение enum
От: SergeyT. США http://sergeyteplyakov.blogspot.com/
Дата: 29.06.13 10:17
Оценка: 2 (1)
Здравствуйте, Аноним, Вы писали:

А>>День добрый!

А>>я понимаю что такой код не будет использоваться в продуктиве (я не сталкивался )
А>>,но объясните поведение enum.

Думаю, что это поправимо.

Перечисление — это такой себе набор именованных констант целочисленного типа, при этом целочисленное значение перечисление может задаваться явно или неявно.

В данном случае приведенные ранее перечисления аналогичны следующему:
enum A : int { aa = 0, ab = 1, ac = 2};
enum B : int { aa = 0, ab = 1, ac = 2};


Таким образом, нижележащим типом перечисления является int, а значения начинаются с 0 и увеличиваются на 1.

Теперь идем дальше.

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

Теперь по шагам:
Console.WriteLine(B.aa + A.ab.ToString());         //aaab

Эквивалентно:
Console.WriteLine(String.Concat((object)B.aa, A.ab.ToString()));

В результате получаем конкатенацию строгового представления перечислений.

Console.WriteLine(B.aa + "---" + A.ab.ToString());   //aaab

Эквивалентно:
Console.WriteLine(String.Concat((object)B.aa, "---", A.ab.ToString()));

Суть та же самая, результат аналогичен предыдущему.

Console.WriteLine(B.aa + 1 + A.ab.ToString());       //abab

Тут уже интересней. На самом деле, есть вариант метода String.Concat, принимающий 3 аргумента, но он перестает быть более подходящим. Поскольку язык C# левоассоциативен (кажется это так называется), поэтому аргумент метода Console.WriteLine рассматривается так: ((B.aa + 1)) + A.ab.ToString().

B.aa + 1 — явлется константой времени компиляции, поэтому это выражение просто заменяется на:

Console.WriteLine(B.ab + A.ab.ToString());

(можно посмотреть в сгенерированный IL никаких операторов + для int-ов там нет).

Тут вообще, момент довольно интересный. Неявные преобразования значений нижележащего типа перечисления к самому перечислению — запрещены (кроме 0), но арифметические операции — разрешены:

B b = 42; //Ошибка!
B b = 0; // Нормально, 0 - это исключение из правил
B b = B.aa + 42; // Нормально
b++; // Тоже нормально
int n = GetValueFromSomewhere();
B b = B.aa + n; // Тоже нормально, т.е. работает не только с константами времени компиляции


Последний вариант:
Console.WriteLine(B.aa + 10 + A.ab.ToString());      //10ab

Здесь мы получаем пример, аналогичный предыдущему. Поскольку B.aa равен 0, то мы получаем следующее:
Console.WriteLine(String.Concat((object)((B.aa)10), A.ab.ToString());

При этом мы получаем 10ab, поскольку ToString при "неизвестном" значении перечисления просто возвращает строковое представление нижележащего значения, в данном случае — это 10.

Если это поведение смущает, то ответ, почему это дело ведет себя именно так можно почитать в: Re: Почему можно -1 привести к Enum
Автор: SergeyT.
Дата: 21.03.13


Да, и я согласен с тем, что поведение не вполне явно, поскольку вполне можно решить, что во всех приведенных примерах будет вызываться разные варианты String.Concat и все.
поведение enum
От: Аноним  
Дата: 28.06.13 01:22
Оценка:
День добрый!
я понимаю что такой код не будет использоваться в продуктиве (я не сталкивался )
,но объясните поведение enum.


    enum A { aa,ab,ac};
    enum B { aa, ab, ac};

    class Program
    {
        static void Main(string[] args)
        {            
            Console.WriteLine(B.aa + A.ab . ToString());         //aaab         
            Console.WriteLine(B.aa + "---" + A.ab.ToString());   //aaab         
            Console.WriteLine(B.aa + 1 + A.ab.ToString());       //abab         
            Console.WriteLine(B.aa + 10 + A.ab.ToString());      //10ab     
            Console.Write((B.aa + A.ab).ToString());             //compile error         
        }
    }
enum
Re: поведение enum
От: Аноним  
Дата: 28.06.13 01:28
Оценка:
Здравствуйте, Аноним, Вы писали:

А>День добрый!

А>я понимаю что такой код не будет использоваться в продуктиве (я не сталкивался )
А>,но объясните поведение enum.


А>
А>    enum A { aa,ab,ac};
А>    enum B { aa, ab, ac};

А>    class Program
А>    {
А>        static void Main(string[] args)
А>        {            
А>            Console.WriteLine(B.aa + A.ab . ToString());         //aaab         
А>            Console.WriteLine(B.aa + "---" + A.ab.ToString());   //aa---ab      
А>            Console.WriteLine(B.aa + 1 + A.ab.ToString());       //abab         
А>            Console.WriteLine(B.aa + 10 + A.ab.ToString());      //10ab     
А>            Console.Write((B.aa + A.ab).ToString());             //compile error         
А>        }
А>    }
А>

поправка

Console.WriteLine(B.aa + "---" + A.ab.ToString());   //aa---ab
Re[2]: поведение enum
От: Ромашка Украина  
Дата: 28.06.13 01:51
Оценка:
Здравствуйте, Аноним, Вы писали:
А>>,но объясните поведение enum.

Так понятнее?
    enum A { aa = 0, ab = 1, ac = 2};
    enum B { aa = 0, ab = 1, ac = 2};



А тут оно просто B к A привести не может.
    Console.Write((B.aa + A.ab).ToString());


Всё, что нас не убивает, ещё горько об этом пожалеет.
Re: поведение enum
От: Doc Россия http://andrey.moveax.ru
Дата: 28.06.13 03:58
Оценка:
Здравствуйте, Аноним, Вы писали:

А>День добрый!

А>я понимаю что такой код не будет использоваться в продуктиве (я не сталкивался )
А>,но объясните поведение enum.

Во всех случаях, кроме последнего, значения перечислений приводятся явно (A.ab.ToString()) или не явно (B.aa + 1) к строке или числу.
В последнем случае компилятор не знает как B привести к A, вот и ошибка.
Re[3]: поведение enum
От: SergeyT. США http://sergeyteplyakov.blogspot.com/
Дата: 29.06.13 10:19
Оценка:
Здравствуйте, SergeyT., Вы писали:

Да, и как уже написали выше, последний вариант не компилируется, поскольку A и B — это два разных типа без каких-либо отношений между собой, и никакие операторы, типа + между ними не определены.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.