Перегруженный индексатор с перечислением: невозможно использовать индексатор по умолчанию

Учитывая следующий код:

namespace MyApp
{
    using System;
    using System.Collections.ObjectModel;

    class Program
    {
        static void Main(string[] args)
        {
            var col = new MyCollection();
            col.Add(new MyItem { Enum = MyEnum.Second });
            col.Add(new MyItem { Enum = MyEnum.First });

            var item = col[0];
            Console.WriteLine("1) Null ? {0}", item == null);

            item = col[MyEnum.Second];
            Console.WriteLine("2) Null ? {0}", item == null);

            Console.ReadKey();
        }
    }

    class MyItem { public MyEnum Enum { get; set; } }

    class MyCollection : Collection
    {
        public MyItem this[MyEnum val]
        {
            get
            {
                foreach (var item in this) { if (item.Enum == val) return item; }
                return null;
            }
        }
    }

    enum MyEnum
    {
        Default = 0,
        First,
        Second
    }
}

Я был удивлен, увидев следующий результат:

1) Null ? True
2) Null ? False

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

Вместо этого кажется, что всегда вызывается перегрузка, ожидающая enum (даже при приведении 0 как int), и тест не проходит.

  1. Может ли кто-нибудь объяснить мне такое поведение?
  2. И предложить обходной путь для поддержки двух индексаторов: одного по индексу, а другого для перечисления?

РЕДАКТИРОВАТЬ : Похоже, что обходной путь заключается в приведении коллекции как Сборник, см. этот ответ .

Итак:

  1. Почему компилятор выбирает наиболее «сложную» перегрузку вместо наиболее очевидной (несмотря на то, что она унаследована)? Считается ли индексатор собственным методом int? (но без предупреждения о том, что вы скрываете родительский индексатор)

Объяснение

С этим кодом мы сталкиваемся с двумя проблемами:

  1. Значение 0 всегда можно преобразовать в любое перечисление.
  2. Среда выполнения всегда начинается с проверки нижнего класса перед копанием в наследовании, поэтому выбирается индексатор перечисления.

Более точные (и лучше сформулированные) ответы см. По следующим ссылкам:

5
задан Community 23 May 2017 в 11:54
поделиться