Home > Software design >  C# Access instance of generic type argument at runtime
C# Access instance of generic type argument at runtime

Time:07-27

I have a handle exception method for my Polly IAsyncPolicy defined as such:

Handle<ApiException>(ApiException ex)
{
 /// do stuff
} 

An ApiException can be either generic or non-generic:

public class ApiException

and

public class ApiException<TResult>

I know that an instance of the generic type will have a Property called Result of type TResult, which will always inherit from a type called BaseResponse.

There are many many classes that inherit from BaseResponse. I want to avoid having to write exception handlers for them all and do it all in the one handler.

At runtime, I want to

a) determine that ex is either a generic or non-generic instance of ApiException and

b) get a reference to the instance if it is generic, and access the "Result" property

I can do a) easily enough with ex.GetType().IsGenericType

b) is proving troublesome

I have tried:

        if (ex is ApiException<> apiE)
        {

        }

But I need a type to go in the <>

I know that type will always inherit from a type called BaseResponse so I tried,

        if (ex is ApiException<BaseResponse> apiE)
        {

        }

but it's not specific enough and returns false for child inheritors e.g ApiException<AuthResponse> where AuthResponse : BaseResponse

Is there anything that can be done?

CodePudding user response:

You can indeed get the type of the generic parameter, you can also read that Result using reflection. Whether you can do anything meaningful with it kind of depends.

static void Handle<T>(T ex) where T : ApiException
{
    var type = typeof(T);
    if(!type.IsGenericType)
    {
        Console.WriteLine($"{type} is non generic");
    }
    else
    {
        var gType = type.GetGenericArguments()[0];
        Console.WriteLine($"{type} is generic, the type is {gType}");
        
        var result = type.GetProperty("Result");
        var obj = (BaseResponse)result.GetValue(ex);
        Console.WriteLine($"Got Result={obj.Name}");
    }
        
}

Live example: https://dotnetfiddle.net/DpyZpk


My "It depends" comment was before I noticed that you commented

I only need to access properties on the base TBaseResult which all TResults will inherit from

So you're in luck.... you can cast that Result

var obj = (BaseResponse)result.GetValue(ex);
// You can call any methods/properties on the base  type
  • Related