.netcore引入了ioc机制让开发人员逐步习惯从过去的各种new对象变成通过IOC框架来管理对象的生命周期。这样当我们需要某个对象的时候,我们一般在构造函数里申明该对象的接口,即可通过ioc容器创建它。但是ioc正常工作的前提是假设我们对ioc使用是正确的,如果不正确的使用ioc则会带来某些意想不到的灾难,比如:

InvalidOperationException: A circular dependency was detected for the service of type 'xxx'

  熟悉.netcore开发的同学应该在初期都会或多或少遇到过这个问题,这个异常代表着你的的ioc容器在创建对象时检测到了对象的循环依赖。简单来讲也就是假设a、b两个对象的构造函数中a依赖了b同时b依赖了a,或者a依赖了b同时b依赖了c同时c依赖了a,ioc容器在创建对象时如果检查不通过则会抛出上面这个异常。解决异常的办法很简单将相关的依赖移除即可,如果在依赖里包含必要的方法调用可以抽离成独立的类型来避免循环依赖,这里不展开讲。今天想说的是假设我们在某些极端的情况下必须要循环依赖时,通过ioc容器如何处理这样的问题。

  如果我们在构造函数里让ioc框架并不去实例化接口对应的实现,而是在具体调用接口方法时才实例化,是否可以解决这个问题呢?聪明的同学应该能够想到通过懒加载的方式应该是可以实现的。不过今天我要讲的并不是Lazy<T>而是通过代理类来实现。下面就是看如何扩展我们的ioc方法来实现一个粗糙版本的懒加载。

  首先我们创建一个空的webhost并申明两个接口

    public interface IAService
{
Task<string> GetWords();
}
public interface IBService
{
Task<string> GetWords();
}

  接着我们对这两个接口编写对应的实现

    public class AService : IAService
{
public AService(IBService callService)
{ }
public async Task<string> GetWords()
{
return await Task.FromResult($"this is AService.GetTest");
}
}
public class BService : IBService
{
public BService(IAService testService)
{ }
public async Task<string> GetWords()
{
return await Task.FromResult($"this is BService.GetTest");
}
}

  然后我们在Startup的ConfigureServices里通过默认的ioc框架注册这两个对象

            services.AddScoped<IAService, AService>();
services.AddScoped<IBService, BService>();

  接下来我们在某个控制器的构造函数里注入IAService

    [ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{
IAService aService;
public TestController(IAService aService)
{
this.aService = aService;
} [HttpGet]
public async Task<string> Get()
{
return await aService.GetWords();
}
}

  此时运行控制台程序。顺利的话当我们访问该控制器下的action时,页面会返回 500 Internal Server Error,同时我们的控制台会打印一个unhandled exception内容如下:

  现在我们来思考一下,如何通过扩展代理的方式来解决这个问题,注意这里仅演示接口-实现的注册方式,直接通过ioc框架将实现-实现注册到容器里并不在本次演示范围内

  首先我们创建一个代理类实现

    public class LazyProxy<TInterface, TImpl> : DispatchProxy
{
protected override object Invoke(MethodInfo targetMethod, object[] args)
{
return "this is lazyservice";
}
}

  接着我们扩展一下IServiceCollection的方法,让我们可以愉快的通过扩展方法来注入代理(*演示仅扩展了Scoped)

 public static class ServiceCollectionExtension
{
public static IServiceCollection AddScopedLazy<TInterface, TImpl>(this IServiceCollection services) where TInterface : class where TImpl : class, TInterface
{
services.AddScoped(typeof(TInterface), x =>
{
var t_proxy = DispatchProxy.Create<TInterface, LazyProxy<TInterface, TImpl>>();
return t_proxy;
});
services.AddScoped(typeof(TImpl), typeof(TImpl));
return services;
}
}

  可以看到这个扩展方法我们并没有将接口和实现作为一对键值对注册到容器中,而是通过接口和代理实例作为一对,实现和实现自己注册成了一对。接下来我们再次访问控制器时正确响应“this is lazyservice”,也就是我们代理类型的Invoke起作用了。其实演示到这里基本已经达到效果了,聪明的你应该能想到在invoke里通过ioc容器将实现类实现出来并调用实现类的同名方法即可调用到真正的实现,从而避免了循环依赖的产生,下面是简单粗暴版:

        protected override object Invoke(MethodInfo targetMethod, object[] args)
{
var impl = serviceProvider.GetService<TImpl>();
return typeof(TImpl).GetMethod(targetMethod.Name).Invoke(impl, args);
}

  再次运行,页面会正确响应“this is AService.GetTest”。接下来看看如何优雅的实现,避免反射性能问题

  优雅的实现有很多方式,比如通过MethodInfo.CreateDelegate的方式构造一个该对象的匿名委托,好处是代码实现比较简单,但是坏处也比较明显,构造委托时必须实例化一个当前类型的实例。同时CreateDelegate本身会有一个性能消耗,如果每次在代理的invoke里去创建方法委托其实并无多大意义,性能上甚至不如反射。如果是提前构造好委托则由于我们构造委托时创建好了实例,导致该实例不会被IOC容器管理起来会有生命周期的问题。第二种则是目前我实现的方法,通过表达式树的方式构造一个匿名委托。代码如下:

  首先我们创建一个委托的工厂类DynamicMethodFactory并提供两个方法,第一个方法用于注册委托并添加到私有字典里,第二个方法用于通过方法查询字典获取委托

    public static class DynamicMethodFactory
{
static Dictionary<MethodInfo, dynamic> DynamicMethods = new Dictionary<MethodInfo, dynamic>();
public static void CreateDynamicMethods<TInterface, TImpl>()
{
foreach (var item in typeof(TImpl).GetMethods().Where(x => x.IsFinal))
{
var key = typeof(TInterface).GetMethods().FirstOrDefault(x => x.Name == item.Name && x.ReturnType == item.ReturnType && x.GetParameters().Select(x => x.ParameterType).SequenceEqual(item.GetParameters().Select(x => x.ParameterType)));
DynamicMethods.TryAdd(key, ExpressionDelegateBuilder.CreateMethodDelegate(typeof(TImpl), item));
}
}
public static object CallDynamicMethod<TImpl>(MethodInfo method, TImpl service, object[] args)
{
DynamicMethods.TryGetValue(method, out dynamic func);
switch (args.Length)
{
default:
throw new ArgumentOutOfRangeException();
case 0:
return func(service);
case 1:
return func(service, args[0]);
case 2:
return func(service, args[0], args[1]);
case 3:
return func(service, args[0], args[1], args[2]);
case 4:
return func(service, args[0], args[1], args[2], args[3]);
case 5:
return func(service, args[0], args[1], args[2], args[3], args[4]);
case 6:
return func(service, args[0], args[1], args[2], args[3], args[4], args[5]);
case 7:
return func(service, args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
case 8:
return func(service, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
case 9:
return func(service, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
case 10:
return func(service, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
case 11:
return func(service, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10]);
case 12:
return func(service, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12]);
case 13:
return func(service, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13]);
case 14:
return func(service, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14]);
case 15:
return func(service, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15]);
}
}
}

  接着我们创造一个表达式树的构造类ExpressionDelegateBuilder用于工厂创建具体的委托

    public static class ExpressionDelegateBuilder
{
public static dynamic CreateMethodDelegate(Type instanceType, MethodInfo method)
{
var callmethod = typeof(ExpressionDelegateBuilder).GetMethods().Where(x => x.ReturnType == typeof(void) ? x.Name == nameof(ExpressionDelegateBuilder.CreateActionMethodDelegate) : x.Name == nameof(ExpressionDelegateBuilder.CreateFuncMethodDelegate)).ToArray()[method.GetParameters().Count()];
var genericType = new List<Type>();
genericType.Add(instanceType);
foreach (var item in method.GetParameters())
{
genericType.Add(item.ParameterType);
}
genericType.Add(method.ReturnType);
return callmethod.MakeGenericMethod(genericType.ToArray()).Invoke(null, new[] { method });
}
public static Func<TObj, Tout> CreateFuncMethodDelegate<TObj, Tout>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Func<TObj, Tout>>(reExpression, pParameter).Compile();
}
public static Func<TObj, dynamic, Tout> CreateFuncMethodDelegate<TObj, T1, Tout>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Func<TObj, dynamic, Tout>>(reExpression, pParameter).Compile();
}
public static Func<TObj, dynamic, dynamic, Tout> CreateFuncMethodDelegate<TObj, T1, T2, Tout>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Func<TObj, dynamic, dynamic, Tout>>(reExpression, pParameter).Compile();
}
public static Func<TObj, dynamic, dynamic, dynamic, Tout> CreateFuncMethodDelegate<TObj, T1, T2, T3, Tout>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Func<TObj, dynamic, dynamic, dynamic, Tout>>(reExpression, pParameter).Compile();
}
public static Func<TObj, dynamic, dynamic, dynamic, dynamic, Tout> CreateFuncMethodDelegate<TObj, T1, T2, T3, T4, Tout>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Func<TObj, dynamic, dynamic, dynamic, dynamic, Tout>>(reExpression, pParameter).Compile();
}
public static Func<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, Tout> CreateFuncMethodDelegate<TObj, T1, T2, T3, T4, T5, Tout>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Func<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, Tout>>(reExpression, pParameter).Compile();
}
public static Func<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, Tout> CreateFuncMethodDelegate<TObj, T1, T2, T3, T4, T5, T6, Tout>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Func<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, Tout>>(reExpression, pParameter).Compile();
}
public static Func<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, Tout> CreateFuncMethodDelegate<TObj, T1, T2, T3, T4, T5, T6, T7, Tout>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Func<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, Tout>>(reExpression, pParameter).Compile();
}
public static Func<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, Tout> CreateFuncMethodDelegate<TObj, T1, T2, T3, T4, T5, T6, T7, T8, Tout>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Func<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, Tout>>(reExpression, pParameter).Compile();
}
public static Func<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, Tout> CreateFuncMethodDelegate<TObj, T1, T2, T3, T4, T5, T6, T7, T8, T9, Tout>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Func<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, Tout>>(reExpression, pParameter).Compile();
}
public static Func<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, Tout> CreateFuncMethodDelegate<TObj, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, Tout>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Func<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, Tout>>(reExpression, pParameter).Compile();
}
public static Func<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, Tout> CreateFuncMethodDelegate<TObj, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, Tout>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Func<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, Tout>>(reExpression, pParameter).Compile();
}
public static Func<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, Tout> CreateFuncMethodDelegate<TObj, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, Tout>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Func<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, Tout>>(reExpression, pParameter).Compile();
}
public static Func<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, Tout> CreateFuncMethodDelegate<TObj, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, Tout>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Func<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, Tout>>(reExpression, pParameter).Compile();
}
public static Func<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, Tout> CreateFuncMethodDelegate<TObj, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, Tout>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Func<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, Tout>>(reExpression, pParameter).Compile();
}
public static Func<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, Tout> CreateFuncMethodDelegate<TObj, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, Tout>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Func<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, Tout>>(reExpression, pParameter).Compile();
}
public static Action<TObj> CreateActionMethodDelegate<TObj>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Action<TObj>>(reExpression, pParameter).Compile();
}
public static Action<TObj, dynamic> CreateActionMethodDelegate<TObj, T1>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Action<TObj, dynamic>>(reExpression, pParameter).Compile();
}
public static Action<TObj, dynamic, dynamic> CreateActionMethodDelegate<TObj, T1, T2>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Action<TObj, dynamic, dynamic>>(reExpression, pParameter).Compile();
} public static Action<TObj, dynamic, dynamic, dynamic> CreateActionMethodDelegate<TObj, T1, T2, T3>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Action<TObj, dynamic, dynamic, dynamic>>(reExpression, pParameter).Compile();
}
public static Action<TObj, dynamic, dynamic, dynamic, dynamic> CreateActionMethodDelegate<TObj, T1, T2, T3, T4>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Action<TObj, dynamic, dynamic, dynamic, dynamic>>(reExpression, pParameter).Compile();
}
public static Action<TObj, dynamic, dynamic, dynamic, dynamic, dynamic> CreateActionMethodDelegate<TObj, T1, T2, T3, T4, T5>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Action<TObj, dynamic, dynamic, dynamic, dynamic, dynamic>>(reExpression, pParameter).Compile();
}
public static Action<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic> CreateActionMethodDelegate<TObj, T1, T2, T3, T4, T5, T6>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Action<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic>>(reExpression, pParameter).Compile();
}
public static Action<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic> CreateActionMethodDelegate<TObj, T1, T2, T3, T4, T5, T6, T7>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Action<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic>>(reExpression, pParameter).Compile();
}
public static Action<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic> CreateActionMethodDelegate<TObj, T1, T2, T3, T4, T5, T6, T7, T8>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Action<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic>>(reExpression, pParameter).Compile();
}
public static Action<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic> CreateActionMethodDelegate<TObj, T1, T2, T3, T4, T5, T6, T7, T8, T9>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Action<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic>>(reExpression, pParameter).Compile();
}
public static Action<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic> CreateActionMethodDelegate<TObj, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Action<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic>>(reExpression, pParameter).Compile();
}
public static Action<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic> CreateActionMethodDelegate<TObj, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Action<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic>>(reExpression, pParameter).Compile();
}
public static Action<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic> CreateActionMethodDelegate<TObj, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Action<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic>>(reExpression, pParameter).Compile();
}
public static Action<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic> CreateActionMethodDelegate<TObj, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Action<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic>>(reExpression, pParameter).Compile();
}
public static Action<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic> CreateActionMethodDelegate<TObj, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Action<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic>>(reExpression, pParameter).Compile();
}
public static Action<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic> CreateActionMethodDelegate<TObj, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(MethodInfo method)
{
var reExpression = GetReturnExpression(typeof(TObj), method, out var pParameter);
return Expression.Lambda<Action<TObj, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic, dynamic>>(reExpression, pParameter).Compile();
}
static UnaryExpression GetReturnExpression(Type objType, MethodInfo method, out List<ParameterExpression> parameterExpressions)
{
var instance = Expression.Parameter(objType, "p");
parameterExpressions = new List<ParameterExpression>();
parameterExpressions.Add(instance);
var mcparamExpression = new List<UnaryExpression>();
foreach (var item in method.GetParameters())
{
var pParameter = Expression.Parameter(typeof(object), "a");
parameterExpressions.Add(pParameter);
mcparamExpression.Add(Expression.Convert(pParameter, item.ParameterType));
}
return Expression.Convert(Expression.Call(instance, method, mcparamExpression.ToArray()), method.ReturnType);
}
}

  最后我们改造一下AddScopedLazy以及LazyProxy

  AddScopedLazy:

        public static IServiceCollection AddScopedLazy<TInterface, TImpl>(this IServiceCollection services) where TInterface : class where TImpl : class, TInterface
{
services.AddScoped(typeof(TInterface), x =>
{
var t_proxy = DispatchProxy.Create<TInterface, LazyProxy<TInterface, TImpl>>() as LazyProxy<TInterface, TImpl>;
t_proxy.serviceProvider = x;
return t_proxy;
});
services.AddScoped(typeof(TImpl), typeof(TImpl));
DynamicMethodFactory.CreateDynamicMethods<TInterface, TImpl>();
return services;
}

  LazyProxy:

    public class LazyProxy<TInterface, TImpl> : DispatchProxy
{
public IServiceProvider serviceProvider;
protected override object Invoke(MethodInfo targetMethod, object[] args)
{
return DynamicMethodFactory.CallDynamicMethod(targetMethod, serviceProvider.GetService<TImpl>(), args);
}
}

  这样我们在启动时会构造一个func<tservice,tin1,tin2,tin....,tout> 这样的匿名委托,当调用代理类的Invoke时,我们会通过工厂获取到这个匿名委托,同时将通过ioc容器创建实现并和参数一起传递进去,从而实现通过委托调用到具体的实现并返回

  结语:当前这套方式只是一个简易的粗糙的实现,大家可以多思考一下是否有更优雅的办法,欢迎评论区留言讨论~

.netcore ioc 循环依赖问题及其相关思考之DispatchProxy的更多相关文章

  1. Spring IoC 循环依赖的处理

    前言 本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本.因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析. 本篇文章主要介绍 Spring IoC 是 ...

  2. Spring IoC - 循环依赖

    Spring 复习 3.循环依赖 3.1 定义 循环依赖指多个对象的创建过程中均需要注入对方对象,如下所示 class A{ B b; public A(){ } public A(B b){ thi ...

  3. 曹工说Spring Boot源码(29)-- Spring 解决循环依赖为什么使用三级缓存,而不是二级缓存

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...

  4. Spring的循环依赖,学就完事了【附源码】

    目录 啥是循环依赖? Spring可以解决循环依赖的条件 Spring如何去解决循环依赖 SpringBean的创建流程 Spring维护的三级缓存 getSingleton getSingleton ...

  5. Spring IOC 容器源码分析 - 循环依赖的解决办法

    1. 简介 本文,我们来看一下 Spring 是如何解决循环依赖问题的.在本篇文章中,我会首先向大家介绍一下什么是循环依赖.然后,进入源码分析阶段.为了更好的说明 Spring 解决循环依赖的办法,我 ...

  6. Spring框架系列(8) - Spring IOC实现原理详解之Bean实例化(生命周期,循环依赖等)

    上文,我们看了IOC设计要点和设计结构:以及Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的:容器中存放的是Bean的定义即Be ...

  7. My.Ioc 代码示例——避免循环依赖

    本文的目的在于通过一些示例,向大家说明 My.Ioc 支持哪些类型的依赖关系.也就是说,如何设计对象不会导致循环依赖. 在 Ioc 世界中,循环依赖是一个顽敌.这不仅因为它会导致 Ioc 容器抛出异常 ...

  8. 展开说说,Spring Bean IOC、AOP 循环依赖

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 延迟满足能给你带来什么? 大学有四年时间,但几乎所有人都是临近毕业才发现找一份好工作 ...

  9. Spring Ioc源码分析系列--自动注入循环依赖的处理

    Spring Ioc源码分析系列--自动注入循环依赖的处理 前言 前面的文章Spring Ioc源码分析系列--Bean实例化过程(二)在讲解到Spring创建bean出现循环依赖的时候并没有深入去分 ...

随机推荐

  1. 如何用JavaDoc命令生成帮助文档

    如何用JavaDoc命令生成帮助文档 文档注释 在代码中使用文档注释的方法 /** *@author *@version * */ 生成帮助文档 打开java文件所在位置,在路径前加入cmd (注意有 ...

  2. Mosquitto

    mosquitto可连接远程服务器及本地服务器. mosquitto可在一个节点内建立一个连接用于收发,也可在一个节点内建立多个连接用于收发.建立一个连接用于收发时,会有初始部分帧的延迟.(可能由于内 ...

  3. JDK源码阅读-FileOutputStream

    本文转载自JDK源码阅读-FileOutputStream 导语 FileOutputStream用户打开文件并获取输出流. 打开文件 public FileOutputStream(File fil ...

  4. 源码分析:Phaser 之更灵活的同步屏障

    简介 Phaser 是 JDK 1.7 开始提供的一个可重复使用的同步屏障,功能类似于CyclicBarrier和CountDownLatch,但使用更灵活,支持对任务的动态调整,并支持分层结构来达到 ...

  5. WPF 数据绑定实例一

    前言: 数据绑定的基本步骤: (1)先声明一个类及其属性 (2)初始化类赋值 (3)在C#代码中把控件DataContext=对象: (4)在界面设计里,控件给要绑定的属性{Binding 绑定类的属 ...

  6. 微信小程序:添加全局的正在加载中图标效果

    在发送请求的时候,显示一个正在加载中的小图标.在加载下一页的时候也显示正在加载中.同时数据请求回来了,把加载中进行关闭. 开发----API-----界面 在哪里添加这两段代码会比较方便呢?一个项目有 ...

  7. 第47天打卡学习(单例模式 深入了解CAS 原子引用 各种锁的理解)

    18彻底玩转 单例模式 饿汉式 DCL懒汉模式 探究! 饿汉式  package com.kuang.single; //饿汉式单例 //单例模式重要思想是构造器私有 public class Hun ...

  8. wxWidgets源码分析(8) - MVC架构

    目录 MVC架构 wxDocManager文档管理器 模板类创建文档对象 视图对象的创建 创建顺序 框架菜单命令的执行过程 wxDocParentFrame菜单入口 wxDocManager类的处理 ...

  9. Leaflet 带箭头轨迹以及沿轨迹带方向的动态marker

    前面写了篇文章,mapboxgl实现带箭头轨迹线,介绍了如何基于mapboxgl实现类似高德地图导航轨迹效果. 下图是我基于leaflet实现的效果. 接下来分享一下在我基于leaflet实现该效果时 ...

  10. 数据库索引知识到MySQL InnoDB

    前言 本文聊聊数据库中的索引,涉及索引基础数据结构,分类.以及使用索引的缺点. 索引就像一本书的目录,商场里面各个楼层指示图,让我们不需要自己无目的的找,而是能够很快的找到自己想要的. 1. 索引的基 ...