Вызов неоднозначного метода CS0121 при вызове индексатора универсального контейнера - PullRequest
0 голосов
/ 15 мая 2019

Я пытаюсь реализовать универсальный контейнер, который можно индексировать обоими способами:

class DoubleIndexer<T1, T2>
{
    public T2 this[T1 key] { get => default; set { } }
    public T1 this[T2 key] { get => default; set { } }
}

Проблема в том, что я получаю ошибки во время компиляции, когда пытаюсь использовать экземпляр одного типа для T1 и T2:

var int_int = new DoubleIndexer<int, int>();
int_int[1] = 13; // CS0121: The call is ambiguous between the following
                 // methods or properties: 'DoubleIndexer<T1, T2>.this[T1]'
                 // and 'DoubleIndexer<T1, T2>.this[T2]'

Нет проблем, когда типы T1 и T2 различаются:

var int_string = new DoubleIndexer<int, string>();
int_string[1] = "Hello"; // OK
int_string["Hello"] = 1; // OK

var int_byte = new DoubleIndexer<int, byte>();
int_byte[1] = 13; // OK
int_byte[(byte)13] = 1; // OK

Есть ли обходной путь для этой проблемы, или я вынужден изменить интерфейс моего универсального класса?

1 Ответ

0 голосов
/ 15 мая 2019

Обходной путь может быть основан на явных интерфейсах :

2-я версия

public interface IDirectIndex<T1, T2>
{
    T2 this[T1 key] { get; set; }
}

public interface IInvertedIndex<T1, T2>
{
    T1 this[T2 key] { get; set; }
}

internal class DoubleIndexer<T1, T2> : IDirectIndex<T1, T2>, IInvertedIndex<T1, T2>
{
    T2 IDirectIndex<T1, T2>.this[T1 key]
    {
        get => default;
        set { Console.WriteLine($"T2 IDirectIndex<T1, T2>.this[T1 key]: {value}"); }
    }

    T1 IInvertedIndex<T1, T2>.this[T2 key]
    {
        get => default;
        set { Console.WriteLine($"T1 IInvertedIndex<T1, T2>.this[T2 key]: {value}"); }
    }
}

Примеры испытаний:

    var int_string = new DoubleIndexer<int, string>();
    ((IDirectIndex<int, string>)int_string)[1] = "Hello"; // OK
    ((IInvertedIndex<int, string>)int_string)["Hello"] = 1; // OK

    var int_byte = new DoubleIndexer<int, byte>();
    ((IInvertedIndex<int, byte>)int_byte)[1] = 134567; // OK
    ((IDirectIndex<int, byte>)int_byte)[134567] = 41; // OK            

    var int_int = new DoubleIndexer<int, int>();
    ((IInvertedIndex<int, int>)int_int)[1] = 1345; // OK
    ((IDirectIndex<int, int>)int_int)[13] = 5431; // OK

1-я версия

public interface IIndex<T1, T2>
{
    T2 this[T1 key] { get; set; }
}

internal class DoubleIndexer<T1, T2> : IIndex<T1, T2>
{
    public T1 this[T2 key]
    {
        get => default;
        set { Console.WriteLine($"T1 this[T2 key]: {value}"); }
    }

    T2 IIndex<T1, T2>.this[T1 key]
    {
        get => default;
        set { Console.WriteLine($"T2 IIndex<T1, T2>.this[T1 key]: {value}"); }
    }
}

Примеры испытаний:

    var int_string = new DoubleIndexer<int, string>();
    ((IIndex<int, string>)int_string)[1] = "Hello"; // OK
    int_string["Hello"] = 1; // OK

    var int_byte = new DoubleIndexer<int, byte>();
    int_byte[1] = 134567; // OK
    ((IIndex<int, byte>)int_byte)[134567] = 41; // OK            

    var int_int = new DoubleIndexer<int, int>();
    int_int[1] = 1345; // OK
    ((IIndex<int, int>)int_int)[13] = 5431; // OK 

Индексаторы MSDN в интерфейсах :

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...