首页 新闻 会员 周边

c# dynamic相关的一个神奇问题

0
悬赏园豆:20 [已解决问题] 解决于 2020-01-09 16:53

自己简单实现的aop功能如果代理类放到控制台项目里是可以成功运行的,放到别的类库里是不能成功的,报错 'System.ValueType' does not contain a definition for 'GetAwaiter'。代码见github https://github.com/wangronghua/DynamicIssue
master分支是报错的,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 移到控制台类库里就能正常运行。

溪爸的主页 溪爸 | 初学一级 | 园豆:134
提问于:2019-12-15 15:05
< >
分享
最佳答案
0

加上强制类型转换试试

dynamic dy = (Task<object>)targetMethod.Invoke(_decorated, args);
收获园豆:10
dudu | 高人七级 |园豆:31007 | 2019-12-15 16:01

这个试过不行的,github里可以直接拉下来运行试下,一天天的被各种疑难杂症折磨

溪爸 | 园豆:134 (初学一级) | 2019-12-15 17:43

@bendanwang: 改为下面这样就不会报错

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

    //var x = await dy;
    return dy;
}
dudu | 园豆:31007 (高人七级) | 2019-12-15 22:00

@dudu: 嗯,我这边有个需求需要实现事务注入,完整的是这样的,所以需要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)
        {
           //开启事务
            var result = InvokeCoore(targetMethod, args).Result;
           //提交事务
            return result;
        }

如果不await的话业务代码还没执行完就执行提交事务操作了,这样就有问题了。或者我这个需求dudu老大有什么好的解决方案?博客园里这类需求是如何解决的?

溪爸 | 园豆:134 (初学一级) | 2019-12-15 22:11

@bendanwang: 要修改 Invoke 方法

protected override Task<object> Invoke(MethodInfo targetMethod, object[] args)
{
    return InvokeCoore(targetMethod, args);
}
dudu | 园豆:31007 (高人七级) | 2019-12-15 22:19

@dudu: 这个基类定死的不能改的吧

溪爸 | 园豆:134 (初学一级) | 2019-12-15 22:28

@bendanwang: 千万千万不要用 .Result

dudu | 园豆:31007 (高人七级) | 2019-12-15 22:30

@dudu: 这里用GetAwaiter().GetResult()吗?应该也不是这个问题吧,相同代码移动到控制台项目里就ok的

溪爸 | 园豆:134 (初学一级) | 2019-12-15 23:02

@dudu: 更神奇的一幕是 调用时不要用匿名类就可以正常运行

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; }
    }
溪爸 | 园豆:134 (初学一级) | 2019-12-16 00:07
其他回答(1)
0

private async Task<object> InvokeCoore(MethodInfo targetMethod, object[] args)
{
dynamic dy = targetMethod.Invoke(_decorated, args);
var x = await dy;
return dy;
}
这段中的 dy 你没办法约束 T 是一个 Task 对象。
试试 把 _decorated 定义为一个 Task<T> 看看

收获园豆:10
gt1987 | 园豆:1150 (小虾三级) | 2019-12-16 08:48

_decorated是代理的对象,这个不用为Task对象,其实这个根本不会是Task对象,dy是_decorated运行的结果,有可能是Task,也有可能是同步结果,比如int,string或者普通model

支持(0) 反对(0) 溪爸 | 园豆:134 (初学一级) | 2019-12-16 11:17

@bendanwang: var x = await dy; 这一句代码 限定了 dy 是一个task 对象。这里要用的话,先作下类型判断。

支持(0) 反对(0) gt1987 | 园豆:1150 (小虾三级) | 2019-12-17 13:24
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册