在Task.Run中动态 [英] dynamic in Task.Run

查看:130
本文介绍了在Task.Run中动态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在不相关的类中,我有一个同名的长期任务.我试图使用动态的通用方法编写此代码.我收到以下错误

I have a long running task with the same name in unrelated classes. I was trying to have this code in common method using dynamic. I am getting following error

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException未通过用户代码处理Message =无法将类型'void'隐式转换为'object'

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException was unhandled by user code Message=Cannot implicitly convert type 'void' to 'object'

我试图将代码隔离到以下内容

I tried to isolate the code to the following

class Program
{
    static void Main(string[] args)
    {
        MainAsync();
        Console.ReadKey();
    }
    static async void MainAsync()
    {
        var classA = new ClassA();
        var classB = new ClassB();
        await RunTask1(classA);
        await RunTask1(classB);
        await RunTask(classA);
        await RunTask(classB);
    }
    static async Task RunTask(dynamic val)
    {
        await Task.Run(() => val.CommonLongRunningTask());
    }
    static async Task RunTask1(ClassA val)
    {
        await Task.Run(() => val.CommonLongRunningTask());
    }
    static async Task RunTask1(ClassB val)
    {
        await Task.Run(() => val.CommonLongRunningTask());
    }
}
internal class ClassA
{
    public void CommonLongRunningTask()
    {
        Console.WriteLine("Class A CommonLongRunningTask");
    }
}
internal class ClassB
{
    public void CommonLongRunningTask()
    {
        Console.WriteLine("Class B CommonLongRunningTask");
    }
}

如果我通过对象本身(RunTask1)而不是动态对象,它将起作用.我试图了解动态传递时发生的情况.

If I pass the object itself (RunTask1) instead of dynamic it works. I am trying to understand what is happening when I am passing in dynamic.

推荐答案

我还无法将其追溯到该语言中的某些内容,但是看来您无法使用动态的lambda表达式 更新:涉及 dynamic 的表达式始终为 dynamic 类型,而不管是否存在void方法调用,请参见 Language Aspects更新

I haven't yet been able to track it back to something in the language, but it appears you can't have an expression lambda with dynamic expression. Update: an expression involving a dynamic is always of type dynamic regardless of whether there's a void method call, see Language Aspects update

lambda语句起作用:

A statement lambda works:

private static async Task RunTask(dynamic val)
{
    await Task.Run(() =>
    {
        val.CommonLongRunningTask();
    });
}

更新:

有效的是,当编译器遇到此情况时:

Update:

Effectively what's going on here is when the compiler encounters this:

() => val.CommonLongRunningTask()

将其解释为等同于:

() => {return val.CommonLongRunningTask();}

...因为在编译时不知道您在 val 上调用的任何内容均不返回任何内容.在运行时,它遇到 val.CommonLongRunningTask()表达式,该表达式的类型为 void ,但是不能将该值返回甚至最小的公共值.分母 object ,从而引发异常消息无法将类型'void'隐式转换为'object'

...since it doesn't know at compile-time that anything you call on val doesn't return anything. At run-time, it encounters the expression val.CommonLongRunningTask() which is of type void but cannot return that value to even the lowest common denominator object and thus throws the exception with message Cannot implicitly convert type 'void' to 'object'

如果按如下方式重新编写 RunTask ,您将有完全相同的例外情况:

You'd have the very same exception if you re-wrote your RunTask as follows:

    private static async Task RunTask(dynamic val)
    {
        await Task.Run(() =>
        {
            return val.CommonLongRunningTask();
        });
    }

语言方面

经过更多的研究/讨论,似乎C#规范的7.5.2节详细说明了为什么会发生这种情况.从本质上讲,任何涉及动态的东西本身就是动态类型(因为在编译时编译器无法知道如何绑定),因此将"val.CommonLongRunningTask()"视为返回动态的东西(因此会出现运行时错误)当它意识到它在运行时无效时.

Language Aspects

After a bit more research/discussion it appears section 7.5.2 of the C# spec details why this is happening. Essentially anything involving a dynamic is itself a dynamic type (because at compile time the compiler cannot know how things will be bound) and thus it views "val.CommonLongRunningTask()" as something that returns dynamic (and thus has a run-time error when it realizes it's void at run-time).

这篇关于在Task.Run中动态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆