首页 > 解决方案 > 等待动态获取错误“System.ValueType”不包含“GetAwaiter”的定义

问题描述

get error 'System.ValueType' does not contain a definition for 'GetAwaiter' 代码见github https://github.com/wangronghua/DynamicIssue 分支master是错误的,branch ok是对的,区别是代理类被移动了到控制台项目。这是代码。

控制台类库

    class Program
    {
        static async Task Main(string[] args)
        {
            var items = (await ProxyDecorator2<IPersonService, PersonService>.Create().GetPartAsync(x => new { x.ID, x.Name }, x => x.ID == 1));

            foreach (var item in items)
            {
                Console.WriteLine(item.ID);
                Console.WriteLine(item.Name);
            }
            Console.WriteLine("结束");
        }
    }

二级图书馆

    public class PersonService: IPersonService
    {

        public ValueTask<List<TResult>> GetPartAsync<TResult>(Func<Person, TResult> selresult, Func<Person, bool> predicate)
        {
            return new ValueTask<List<TResult>>(dataSource.Where(predicate).Select(selresult).ToList());
        }

        private static List<Person> dataSource=new List<Person>
        {
            new Person{ ID = 1,Name = "张三"},
            new Person{ ID = 2,Name = "李四"}
        };
    }

    public interface IPersonService
    {
        ValueTask<List<TResult>> GetPartAsync<TResult>(Func<Person, TResult> selresult, Func<Person, bool> predicate);
    }
    public class Person
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }
    public class ProxyDecorator2<T, TClass> : DispatchProxy where T : class where TClass : T, new()
    {
        protected T _decorated;

        public static T Create()
        {
            var proxy = Create<T, ProxyDecorator2<T, TClass>>();
            var proxyReal = proxy as ProxyDecorator2<T, TClass>;
            if (proxyReal == null) throw new Exception("proxyReal报错");
            proxyReal._decorated = new TClass();
            return proxy;
        }
        private async Task<object> InvokeCoore(MethodInfo targetMethod, object[] args)
        {
            dynamic dy = targetMethod.Invoke(_decorated, args);
            var x = await dy;
            return dy;
        }
        protected override object Invoke(MethodInfo targetMethod, object[] args)
        {
            return InvokeCoore(targetMethod, args).Result;
        }
    }

将proxydecorator2移至控制台类库即可正常运行。

更新1

嗯,我有个事务注入的需求,已经完成了,所以需要await任务

        private async Task<object> InvokeCoore(MethodInfo targetMethod, object[] args)
        {
            dynamic dy = targetMethod.Invoke(_decorated, args);
            var x = await dy;
            return dy;
        }
        protected override object Invoke(MethodInfo targetMethod, object[] args)
        {
           //Open transaction
            var result = InvokeCoore(targetMethod, args).Result;
           //commit transaction
            return result;
        }

如果不等待,业务代码会在执行完成之前执行commit事务,所以有问题。或者什么是满足我需求的好方法?

更新2

更神奇的是,调用的时候不用匿名类也能正常运行

var items = (await ProxyDecorator2<IPersonService, PersonService>.Create().GetPartAsync(x => new AA { ID = x.ID, Name= x.Name }, x => x.ID == 1));

public class AA
{
    public int ID { get; set; }
    public string Name { get; set; }
}

标签: c#dynamicasync-await

解决方案


我冒昧地克隆了您的代码。

问题出在以下几行:

dynamic dy = targetMethod.Invoke(_decorated, args);
var x = await dy;

更改dynamicvar,你会得到一个错误,说object是不可等待的。

所以要修复它,请更改您的代码

private object InvokeCoore(MethodInfo targetMethod, object[] args)
{
    var dy = targetMethod.Invoke(_decorated, args);
    return dy;
}

protected override object Invoke(MethodInfo targetMethod, object[] args)
{
    return InvokeCoore(targetMethod, args);
}

或者,如果您不想更改 InvokeCoore 的签名:

private Task<object> InvokeCoore(MethodInfo targetMethod, object[] args)
{
    var dy = targetMethod.Invoke(_decorated, args);
    return Task.FromResult(dy);
}

更新:我试图比较代码,看看编译器是否足够聪明,可以确定你根本不需要 Async,所以它只是没有编译成状态机。但事实并非如此。查看 Sharplab 上的代码似乎差别不大。


推荐阅读