繁体   English   中英

检查对象是任务还是任务<TResult>

[英]Check if Object is Task or Task<TResult>

在下面的示例代码(由于 if 检查无效而无法编译)中,我需要确定 returnValue 是“TResult 任务”还是任务或其他类型。 如果是 TResult 的任务,我可以访问并记录 Result 属性,如果是任务,则没有返回值并记录“[任务]”,如果两者都不是,则我可以直接记录返回值或记录一个[“空”]

public void LogReturnValue(obj returnValue)
{
   var valueToLog = "";
   if(returnValue is Task)
   {
       valueToLog = "[Task]";
   } else if(returnValue is Task<T>)
   {
     valueToLog = returnValue.Result;
   } 
   else 
   {
     valueToLog = returnValue ?? "[null]"
   }
   this.logger.Log(valueToLog);
}

我想确定 returnValue 是 TResult 的任务还是任务,然后如果是后者,我需要从结果中提取适当的值。 我的一个想法是检查 IsGenericType 属性,但我不确定这是否总是有效。

尽管 Eric Lippert 提到您不应获取 Task.Result,但仍有几个问题需要回答:

  1. 如何检查对象是否为泛型类型

    obj.GetType().IsGenericType
  2. 是否是 Task<TResult>

     obj.GetType().GetGenericTypeDefinition() == typeof(Task<>)
  3. 如何访问通用属性值

    obj.GetType().GetProperty("Result").GetValue(obj) // This value could be null

可能有一种更简洁的方法,但这是有效的,您可以在此基础上进行构建。 “as”将检查类型或基类型是一个任务,然后您可以检查该类型以查看它是否具有泛型类型参数。 因为它是动态的,所以检查 Result 是否是一个属性是在运行时而不是编译时完成的。

static void outType(object returnValue)
{
    dynamic task = returnValue as Task;
    if ( task != null )
    {
        var gargs = returnValue.GetType().GenericTypeArguments;

        if (gargs.Count() == 0)
        {
            Console.WriteLine("Task");
        }
        else
        {
            var result = task.IsCompleted ? task.Result : "[Not Complete]";
            Console.WriteLine("Task<{0}> : {1}", gargs[0].Name, result);
        }
    }
}

我觉得要么前面的答案都没有明确回答所提出的问题,要么我错过了问题意图的标记。

我从问题中解释的是:

“我如何判断 'returnValue' 是类型 'Task'、'Task<>' 还是其他类型?

此测试代码可用于确定这一点:

    Task voidTask = new Task(() => { return; });
    Task<object> valTask = new Task<object>(() => { return null; });

    Type voidTaskType = voidTask.GetType();
    Type valTaskType = valTask.GetType();

    Console.WriteLine($"voidTaskType is Task : {voidTask is Task}");
    Console.WriteLine($"valTaskType is Task : {valTask is Task}");
    Console.WriteLine($"voidTaskType.IsGenericType : {voidTaskType.IsGenericType}");
    Console.WriteLine($"valTaskType.IsGenericType : {valTaskType.IsGenericType}");

结果如下:

voidTaskType is Task : True
valTaskType is Task : True
voidTaskType.IsGenericType : False
valTaskType.IsGenericType : True

让我们保持简单,好吗? 这种方法会给你的想法:

object GetTaskResult(Task task, out bool hasResult) {
    var resultProperty = task.GetType().GetProperty("Result");
    hasResult = resultProperty != null;
    return hasResult ? resultProperty.GetValue(task) : null;
}

它告诉您任务是否有结果,如果有则返回结果。

替代版本

bool GetTaskResult(Task task, out object result) {
    var resultProperty = task.GetType().GetProperty("Result");
    if (resultProperty == null) {
        result = null;
        return false;
    }
    result = resultProperty.GetValue(task);
    return true;
}

我已经针对VoidTaskResult对其进行了测试,并且可以正常工作。

我注意到在.Net 5中,null 属性访问器?. 永远不需要,因为所有任务都存在Result属性。 它被初始化为System.Threading.Tasks.VoidTaskResult 这不是获取价值的最有效方法,但它很简洁。

var result = task.GetType().GetProperty(nameof(Task<object>.Result))?.GetValue(task);

这可能会有所帮助。

使用:

类型 type = abc.GetType().GetProperty("Item").PropertyType

参考: 如何从泛型类或方法的成员中获取T的类型?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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