自己简单实现的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 移到控制台类库里就能正常运行。
加上强制类型转换试试
dynamic dy = (Task<object>)targetMethod.Invoke(_decorated, args);
这个试过不行的,github里可以直接拉下来运行试下,一天天的被各种疑难杂症折磨
@bendanwang: 改为下面这样就不会报错
private async Task<object> InvokeCoore(MethodInfo targetMethod, object[] args)
{
var dy = targetMethod.Invoke(_decorated, args);
//var x = await dy;
return dy;
}
@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老大有什么好的解决方案?博客园里这类需求是如何解决的?
@bendanwang: 要修改 Invoke 方法
protected override Task<object> Invoke(MethodInfo targetMethod, object[] args)
{
return InvokeCoore(targetMethod, args);
}
@dudu: 这个基类定死的不能改的吧
@bendanwang: 千万千万不要用 .Result
@dudu: 这里用GetAwaiter().GetResult()吗?应该也不是这个问题吧,相同代码移动到控制台项目里就ok的
@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; }
}
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> 看看
_decorated是代理的对象,这个不用为Task对象,其实这个根本不会是Task对象,dy是_decorated运行的结果,有可能是Task,也有可能是同步结果,比如int,string或者普通model
@bendanwang: var x = await dy; 这一句代码 限定了 dy 是一个task 对象。这里要用的话,先作下类型判断。