Ограничение struct
на Nullable<T>
ИМХО действительно неудачно. Что-то вроде Nullable<String>
или Nullable<Nullable<Nullable<int>>>
может быть расточительным, но что с того? Бокс первый как его содержание; распакуйте его как его содержимое и установите HasValue
, если содержимое не равно нулю. Пометьте первый как int
, если во всех обнуляемых отчетах HasValue
, а при распаковке установите HasValue
всех вложенных элементов, если содержимое было ненулевым.
В противном случае я бы предложил создать статический универсальный класс с параметром типа T
, который содержит свойство делегата, принимающее T
в качестве параметра. Свойство должно возвращать содержимое частного поля, которое должно быть инициализировано, чтобы указывать на метод, который будет проверять тип T
и устанавливать для делегата либо версию struct
, либо class
, в зависимости от ситуации.
Вот пример того, о чем я говорю; в этом используются различные ограничения интерфейса, а не ограничения структуры / класса, но те же принципы могут использоваться так же эффективно.
static class _FooDispatcher<T>
{
public static Action<T> Foo = setupFoo;
static void doFooWithIGoodFoo<TT>(TT param) where TT : IGoodFoo
{
Console.WriteLine("Dispatching as IGoodFoo with {1} type {0}", typeof(TT).ToString(), typeof(TT).IsValueType ? "value" : "reference");
param.Foo();
}
static void doFooWithIOkayFoo<TT>(TT param) where TT : IOkayFoo
{
Console.WriteLine("Dispatching as IOkayFoo with {1} type {0}", typeof(TT).ToString(), typeof(TT).IsValueType ? "value" : "reference");
param.Foo();
}
static void doFooSomehow<TT>(TT param)
{
Console.WriteLine("Nothing exciting with {1} type {0}", typeof(TT).ToString(), typeof(TT).IsValueType ? "value" : "reference");
}
static void setupFoo(T param)
{
System.Reflection.MethodInfo mi;
if (typeof(IGoodFoo).IsAssignableFrom(typeof(T)))
mi = typeof(_FooDispatcher<T>).GetMethod("doFooWithIGoodFoo", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
else if (typeof(IOkayFoo).IsAssignableFrom(typeof(T)))
mi = typeof(_FooDispatcher<T>).GetMethod("doFooWithIOkayFoo", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
else
mi = typeof(_FooDispatcher<T>).GetMethod("doFooSomehow", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
Foo = (Action<T>)(@Delegate.CreateDelegate(typeof(Action<T>), mi.MakeGenericMethod(typeof(T))));
Foo(param);
}
}