Я бы хотел сделать такую функцию, как показано ниже. 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
является ссылочным типом!
Итак, могу ли я как-то написать реализацию, чтобы она была действительной для обоих случаев?
Линия 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()
, тогда конкретный метод будет ПИНА - даже если я упрощу первый шаг, назвав четыре реализации по-разному;
Сделайте четыре производных класса, каждый с другим именем. Это испортит иерархию классов.
Короче говоря, этот способ полностью непригоден.
Вы можете указать 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>
, вам понадобятся четыре перегрузки, чтобы позаботиться обо всех возможных комбинациях.
Вы должны иметь возможность иметь все четыре перегрузки совместно использовать общую реализацию, обрабатывая нулевые тесты в каждой перегрузке, а затем вызывая общий метод реализации, который не заботится о нулях (т.е. Можно смело предположить, что они были адресованы).
Nullable
. Я отредактировал вопрос, чтобы подчеркнуть это.Nullable<T>
вы должны добавить ограничениеwhere T : struct
.