简体   繁体   中英

How to use underlying generic types of generics C#

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.

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM