C# универсальная неоднозначность причины типов

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

class Widget< T1, T2>
{
    ...
    public bool Bar( T1 type1 )
    {
        ...
    }
    public bool Bar( T2 type2 )
    {
        ...
    }
    ...
}

Следующие строки, конечно, создают неоднозначную ошибку компиляции вызова:

Widget<int, int> Foo = new Widget<int, int>();
...
Foo.Bar(5);
...

Есть ли какой-либо путь вокруг этого? Есть ли пункт, который я могу поместить вроде "где: TypeOf (T1)! = TypeOf (T2)" или какой-либо способ сделать этот disambiguous? Предпочтительно интервал, интервал был бы доступен, но это не manditory.

Обновление:

Я на самом деле самостоятельно обнаружил приемлемое решение (для меня) к этой проблеме для тех, кому интересно

class Widget< T1, T2>
{
    ...
    public bool Bar( object o )
    {
        if( o.GetType() == typeof(T1) )
        {
            ...
        }
        if( o.GetType() == typeof(T2) )
        {
            ...
        }
    }
    ...
}
7
задан Steve H. 25 February 2010 в 16:42
поделиться

4 ответа

Есть ли предложение, которое я могу поместить в строки "where: TypeOf (T1)! = TypeOf (T2 ) "

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

Есть ли способ сделать это недвусмысленным?

Вы должны изменить имена ваших методов, чтобы они не конфликтовали. Это, безусловно, самый безопасный и простой способ сделать.

Фактически, IIRC CLR оставляет за собой право не создавать тип, который приводит к подобной неоднозначности в сигнатурах методов. (Очевидно, что наша реализация действительно успешна, но вы ступаете по очень тонкому льду, когда тянете за подобного рода махинации.)

Делать такие вещи - действительно, очень плохая идея, потому что это может привести к всевозможным неприятностям. . Вот пример того, как дела идут ужасно неправильно:

http://blogs.msdn.com/ericlippert/archive/2006/04/05/odious-ambiguous-overloads-part-one.aspx

http: / /blogs.msdn.com/ericlippert/archive/2006/04/06/odious-ambiguous-overloads-part-two.aspx

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

class C<T, U> : IFoo<T>, IFoo<U> { ... }

, потому что тогда вы могли бы построить C , и у CLR не было бы способа узнать, какие методы соответствуют каким интерфейсным слотам.

Но я, кажется, немного отвлекся. Вернемся к теме.

Поскольку вы являетесь создателем этого класса, вы можете переименовать свои методы «Бар», чтобы они были разными при любой возможной конструкции. Предположим, вы упорно решаете не делать этого. Может ли пользователь вашего несчастного класса сделать что-нибудь, если он захочет сделать Widget ? Да, на самом деле, как указывает kvb, есть. Они могут определять методы расширения, которые поступают правильно .

public static void BarTheFirst<A, B>(this Widget<A, B> w, A a)
{
    w.Bar(a);
}

public static void BarTheFirst<A, B>(this Widget<A, B> w, B b)
{
    w.Bar(b);
}

Разрешение перегрузки выполняется во время компиляции , и во время компиляции все, что мы знаем, это то, что первый вызывает Bar, который принимает "A", а второй вызывает Bar, который принимает " B ". Мы не повторно выполняем разрешение перегрузки во время выполнения, поэтому теперь вы можете сказать

Widget<int, int> w = whatever;
w.BarTheFirst(5);
w.BarTheSecond(10);

, и он будет действовать правильно.

19
ответ дан 6 December 2019 в 07:50
поделиться

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

abstract class WidgetBase<T1>
{

    public abstract bool Bar(T1 type);
    ... 
}

Затем наследуйте для ваша реализация

class WidgetA : WidgetBase<int>
{
     public bool Bar(int type)
     {
         ...
     }
}

class WidgetB : WidgetBase<int>
{
     public bool Bar(int type)
     {
         ...
     }
}
0
ответ дан 6 December 2019 в 07:50
поделиться

Дайте вашим функциям уникальные имена

3
ответ дан 6 December 2019 в 07:50
поделиться

Я согласен с другими, что вам следует изменить свой класс, чтобы не происходило столкновения (например, путем переименования методов). Однако, если вы не владеете классом, есть обходной путь:

public static class WidgetExtensions
{
    public static bool Bar1<T1,T2>(this Widget<T1, T2> w, T1 t1) { return w.Bar(t1); }
    public static bool Bar2<T1,T2>(this Widget<T1, T2> w, T2 t2) { return w.Bar(t2); }
}

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

1
ответ дан 6 December 2019 в 07:50
поделиться
Другие вопросы по тегам:

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