Reputation: 6382
I have an internal generic method byte[] catchAllOperation<T>(T genericItem)
and another one byte[] arrayOperation<T>(T[] genericArray)
. Additionally, I have a highly specialized operation byte[] specializedOperation<TKey,TValue>(CustomMap<Tkey,TValue> customMap)
.
How to write a method like this? (pseudocode):
public byte[] universalOperation<T>(T anything){
if(T is CustomMap<UKey,UValue>){ // UKey/UValue are unknown
return specializedOperation<UKey,UValue>(anything);
} else if(T is U[]){ // U is unknown
return arrayOperation<U>(anything);
}else{
return catchAllOperation<T>(anything);
}
}
How to get U
and how to call arrayOperation<U>(anything);
with U
if I have only T
(and the same for CustomMap<>
)? Most questions I have seen assume that U
is already known. Serializers use reflection to construct a separate method for each concrete type and then cache the method. But here I only want to redirect/dispatch a universal method to special cases when I could detect these cases.
I will have more types similar to CustomMap
, so there is time to make any radical changes to code/approach. All special methods leverage the fact that for blittable underlying types some transformations and custom layout significantly boost the compression ratio of custom types. For custom types I could implement an interface, but for generic arrays it is not an option.
Upvotes: 1
Views: 110
Reputation:
Like you are able to read comments it is not possible with generics. The only type is T
do getting U
and other types is not possible without reflection.
Sample solution:
public static void UniversalOperation<T>(T anything)
{
// check for null etc.
var anythingType = anything.GetType();
if (anythingType.IsGenericType &&
anythingType.GetGenericTypeDefinition() == typeof(CustomMap<,>))
{
var genericArgs = anythingType.GetGenericArguments();
var keyType = genericArgs[0];
var valueType = genericArgs[1];
return specializedOperation(keyValue, valueType, anything);
}
else if (anythingType.IsArray)
{
var elemType = anythingType.GetElementType();
return arrayOperation(elemType, anything);
}
else
{
//T is parameter, so you can pass it
catchAllOperation<T>(anything);
}
}
Unfortunately, solution above required non-generic version of specializedOperation
. Anyway, most of serializes (did I understand corretly, you serialize it?) share with non-generic overloads.
Upvotes: 1
Reputation: 1500785
Your question isn't entirely clear to me, but it sounds like you basically need to look in typeof(T)
with reflection. Fortunately, dynamic typing in C# means you can get the compiler team to do the hard work - admittedly at execution time:
// Note: all names changed to be more conventional
public byte[] UniversalOperation<T>(T value)
{
dynamic d = value;
return DynamicOperation(d);
}
private byte[] DynamicOperation<UKey, UValue>(CustomMap<UKey, UValue> map)
{
// Do stuff with the map here
}
private byte[] DynamicOperation<U>(U[] array)
{
// Do something with the array here
}
private byte[] DynamicOperation(object value)
{
// Fallback
}
Note that your UniversalOperation
method doesn't have to be generic now - it will just use the execution-time type of the value. Of course, that means it may not be quite as you originally intended - for example, if the value is null
, you're in trouble - whereas you could have potentially worked with typeof(T)
despite that. Without knowing what you're trying to achieve, we can't tell whether or not that's a problem.
Upvotes: 5