insighter
@insighter
-First time? - Huh? (C#, React, JS)

Почему не работает перегрузка оператора неявного преобразования типа?

Если кратко, то хотел сделать обвертку для перебора всех значений enum через оператор foreach.
Забегая вперед скажу что задачу решил другим способом, меньшим количеством кода. Но совершенно не понимаю почему не работает данный вариант решения.

public enum DirEnum { Up, Down };

// класс-обвертка над DirEnum

    public class Dir
    {
        private readonly DirEnum Value;
        private static readonly DirEnum[] ValuesArray;

        static Dir()
        {
            ValuesArray = new DirEnum[] { DirEnum.Up, DirEnum.Down };
        }

        public Dir(DirEnum value) => Value = value;

        public static Array Values { get => ValuesArray; }

        // перегруженные операторы неявного преобразования

        public static implicit operator DirEnum (Dir instance) => instance.Value;   // DirEnum = Dir
        public static implicit operator Dir (DirEnum value) => new(value);          // Dir = DirEnum
    }

// код ниже отлично работает, кастинг в обе стороны

Dir temp = new (DirEnum.Up);
DirEnum tempEnum = DirEnum.Down;
temp = tempEnum;
tempEnum = temp;


А вот далее на строке с оператором foreach, вываливается исключение Unable to cast object of type 'DirEnum' to type 'Dir'

foreach (Dir a in Dir.Values) {
    tempEnum = a;
    MessageBox.Show(tempEnum.ToString());
}


UPD
Задача создания обвертки над enum'ом для регулярного перебора через foreach, решается в 2 строки:
public enum Dir { Up, Down };
        public class Dirs
        {
            public static Dir[] All { get => (Dir[])Enum.GetValues(typeof(Dir)); }
        }
  • Вопрос задан
  • 126 просмотров
Решения вопроса 1
Невероятно, но я разгадал в чём проблема.
Проблема кроется в том, что вы используете класс Array
public static Array Values { get => ValuesArray; }
Когда вы используете Array внутри foreach, то с ним происходит работа как с System.Collections.IEnumerable (не Generic).
Тоесть каст будет происходить не DirEnum->Dir, а Object->Dir
Как доказательство, вот кусочек IL:
IL_000e: callvirt     instance object [System.Runtime]System.Collections.IEnumerator::get_Current()
IL_0013: castclass    Dir

Более упрощённо можно повторить эту проблему, если сделать так:
DirEnum a = DirEnum.Up;
object box = x;
Dir y = (Dir) box; // Казалось бы, у нас есть оператор DirEnum->Dir, но вызываться будет castClass, а не переопределённый оператор

Если заменить Array на IReadOnlyCollection<DirEnum>, то всё будет ок.
Ну или если вместо Dir в foreach взять DirEnum

PS:
Суффиксы Enum и Array у имён нужны. Лучше бы назавали DirEnum - Direction, Dir - DirectionBox, а ValuesArray - allValues, это кстати тоже не нужно, тк есть метод Enum.GetValues
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы