Home > Software design >  cast object Task<ActionResult<T>> where T is Type variable
cast object Task<ActionResult<T>> where T is Type variable

Time:07-06

I'm making a unit test class with a config file. I have similar object (same interfaces) to check.

At a point of my code I get Task<ActionResult<OneOfMyObjectType>> object by using reflection. my issue is to read the Result I have to cast this Object First but I can't use Task<IActionResult> or Task<ActionResult<InferfaceOfTheObject>>. the compiler only allow me to cast to the Specific class that is used. (if I don't I have an InvalidCastException).

How Can I do this?

extract of code of my tests :

dynamic objectType = Type.GetType($"{ClassName},{Assembly}")!;
Type ControllerActionType = Type.GetType($"{ControllerActionsClasseName}, {Assembly}")!;
MethodInfo info = ControllerActionType.GetMethod(methodName!)!;
var myInstance = Activator.CreateInstance(ControllerActionType, new object[] { context });
var testObject = JsonConvert.DeserializeObject(operation!.Data, objectType);
var actionResult = info!.Invoke(myInstance, new object[] { testObject })!;
var castedActionResult = "** I'm blocked here**";

CodePudding user response:

Without more information, my guess is that Controller.Method returns a Task, and that you're trying to cast the result from the method as Task<ActionResult>.

All you need to here is two casts, one that matches the return type from the method, and one on the Task's result that is the expected underlying type.

var actionResultTask = (Task<IActionResult>)info!.Invoke(myInstance, new object[] { testObject })!;
var castedActionResult = (ActionResult<InferfaceOfTheObject>) = actionResultTask.Value;

The point here, is that without a lot more reflection, the generic parameters must match. So if the ActionResult from method was declared with the interface, then it has to be casted ActionResult<InterfaceOfTheObject>, if it was declared using an implementation then that cast has to be used instead.

If you're unsure of a type of a property, but are confident that its return type implements a relevant interface, then you can use the following method to get the property value by reflection. You should be able to use this to get any property value.

public void SomeTestMethod() {
    /* ... */
    var methodResult = (Task)info.Invoke(myInstance, new object[] {});
    var actionResult = GetGenericPropertyValue<IActionResult>(methodResult, "Result");
    var actionResultValue = GetGenericPropertyValue<InferfaceOfTheObject>(actionResult, "Value");
}
    
public static T GetGenericPropertyValue<T>(object obj, string propertyName)
{
    return (T)obj.GetType().GetProperty(propertyName).GetValue(obj);
}
  • Related