использовать разные сигнатуры функций для типов значений и ссылочных типов

1

Я бы хотел сделать такую функцию, как показано ниже. K и L являются типичными параметрами типа. (это настройка MultiKeyDictionary by Aron Weiler в случае, если вы задаетесь вопросом)

protected void Dissociate(K primaryKey, L subKey)
{
    primaryToSubkeyMapping.Remove(primaryKey??subDictionary[subKey]);
    subDictionary.Remove(subKey??primaryToSubkeyMapping[primaryKey]);
}

Каждый аргумент является необязательным, но по крайней мере один должен присутствовать; null означает отсутствие. Проблема в том, что если общий параметр является типом значения, мне нужно обернуть аргумент функции с помощью Nullable so primaryKey?? и поэтому я могу передать значение null чтобы указать отсутствие аргумента. Но, Nullable<K> недействителен, если вместо этого K является ссылочным типом!

Итак, могу ли я как-то написать реализацию, чтобы она была действительной для обоих случаев?

  • 0
    Обратите внимание на тот факт, что мне нужно обернуть тип значения в Nullable . Я отредактировал вопрос, чтобы подчеркнуть это.
  • 1
    Вы хотите сделать их обнуляемыми, а также передавать ссылочные типы одновременно? если это невозможно, для того, чтобы сделать их Nullable<T> вы должны добавить ограничение where T : struct .
Показать ещё 2 комментария
Теги:
generics

2 ответа

0
Лучший ответ

Линия Botton: это можно сделать, но требует непропорционального объема накладных расходов. Так что это совершенно непрактично.

В конце концов, я решил это, добавив два перегруженных метода без аргумента.


В соответствии со спецификацией С# v.3.0, §B.2.7, ограничения типа могут быть помещены в одиночные методы. Но эти методы должны иметь типы, на которые накладываются ограничения, как их собственные параметры типа. Итак, я смог сделать трюк следующим образом:

protected void Dissociate<KP,LP>(KP? primaryKey, LP? subKey)
    where KP:struct,K where LP:struct,L
{
    primaryToSubkeyMapping.Remove(primaryKey??subDictionary[subKey.Value]);
    subDictionary.Remove(subKey??primaryToSubkeyMapping[primaryKey.Value]);
}

Но теперь мне нужно сделать четыре реализации для каждой комбинации class и struct ! И когда я пытаюсь вызвать их внутри typeof(K).IsValueType -like проверяет, компилятор не может получить его как подсказку для разрешения перегрузки и дает соответствующую ошибку. Именование их по-разному идет только на один шаг: компилятор не убежден, что только один из них когда-либо будет вызываться в любой конкретной реализации и все еще не выполняет проверки типа аргумента. Теперь есть два варианта:

  • Вызовите соответствующую реализацию посредством размышлений. Получение объектов типа универсального типа для GetMethod(), тогда конкретный метод будет ПИНА - даже если я упрощу первый шаг, назвав четыре реализации по-разному;

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

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

    Короче говоря, этот способ полностью непригоден.

0

Вы можете указать Nullable<T> в качестве типа параметра, чтобы разрешить перегрузку. Например:

class A { }
struct B { }

class Program
{
    static void Main(string[] args)
    {
        A a = new A();
        B? b = new B();

        Method(a);
        Method(b);

        a = null;
        b = null;

        Method(a);
        Method(b);
    }

    static void Method<T>(T t) where T : class
    {
        Console.WriteLine("Reference type: " + (t != null ? "not " : "") + "null");
    }

    static void Method<T>(Nullable<T> t) where T : struct
    {
        Console.WriteLine("Nullable<T> type: " + (t != null ? "not " : "") + "null");
    }
}

В вашем собственном сценарии, если параметры типа K и L могут быть независимо ссылочным типом или Nullable<T>, вам понадобятся четыре перегрузки, чтобы позаботиться обо всех возможных комбинациях.

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

  • 0
    На описанном вами шаге у меня возникла проблема, заключающаяся в том, что я не мог указать компилятору, какой перегруженный метод использовать, если я попытался вызвать их из другого кода в том же родовом классе.
  • 0
    Да. Из вопроса не было ясно, что вызывающий абонент также является общим. Чтобы разрешение перегрузки работало, компилятору необходимо знать во время компиляции, какие типы и ограничения действуют, что было бы невозможно, если бы он вызывался из универсального типа без каких-либо ограничений. Прости за это.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню