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

  • 问题

  • 自己简单实现的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 移到控制台类库里就能正常运行。



    2019年12月15日 7:19

全部回复

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

    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; }
        }

    2019年12月15日 16:08
  • Hi,

    我重现了您的问题,我建议你可以做出以下更改。

    把下面的代码替换到相应的地方。

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

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2019年12月16日 7:50
    版主
  • 我这边有个需求需要实现事务注入,完整的是这样的,所以需要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的话业务代码还没执行完就执行提交事务操作了,这样就有问题了。或者我这个需求有什么好的解决方案?
    2019年12月17日 1:09
  • Hi

    感谢您的反馈。

    如果你想要设置await来执行方法,你可以参照以下方法。

     private async Task<object> InvokeCoore(MethodInfo targetMethod, object[] args)
            {
                object dy = null ;
                await Task.Run(()=> { dy = targetMethod.Invoke(_decorated, args); });
                return dy;
            }

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2019年12月17日 2:24
    版主
  • 感谢你的回复,

    await Task.Run(()=> { dy = targetMethod.Invoke(_decorated, args); });

    这个await只是Task.Run返回的Task完成了,但是targetMethod.Invoke(_decorated, args)返回的ValueTask<List<TResult>>其实是还未完成的。图片上传不了,这是调试截图地址   https://social.msdn.microsoft.com/Forums/getfile/1515206

    2019年12月17日 3:09
  • Hi

    你的意思是你还需要对 Invoke方法进行事务注入吗?

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2019年12月17日 3:12
    版主
  • 是的,这个是事务注入的通用方法,代码类似这种的。

            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)
            {
               using(var transactionScope = new TransactionScope(
                    TransactionScopeOption.Required,
                    new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted })){
               	 	var result = InvokeCoore(targetMethod, args).Result;
               		transactionScope.Complete();
                		return result;
    	}
            }

    2019年12月17日 3:24
  • Hi 

    你上传的图片我看不了,我不太明确你当前的问题出在了哪里。请尝试重新上传图片。

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2019年12月17日 5:31
    版主