.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. vueJS+ES6开发移动端APP实战项目笔记

    一.什么是MVVM框架 MV*包括MVC.MVP.MVVM MVVM框架由Model.View.ViewModel构成. Model指的是数据,在前端对应的是JavaScript对象. View指的是 ...

  2. NGK全球行伦敦站,SPC推动全球数字金融创新

    近日,NGK全球巡回路演在英国的首都伦敦盛大落幕,此次路演有幸邀请到了西欧区块链业界弗洛伊德大咖,NGK方面代表鲍利斯以及英国及其组周边国家社群意见代表马丁内斯等人,总计参与人数达到了数十人. 路演一 ...

  3. 伦尼斯酒庄(Chateau Renice)再次赞助亚洲50大餐厅赛事

    连续几年来,伦尼斯酒庄(Chateau Renice)一直是亚洲50大最佳餐厅评选赛(Asia's 50 Best Restaurant Awards)的赞助商.2020年伦尼斯酒庄酒庄(Chatea ...

  4. 采用lua脚本获取mysql、redis数据以及jwt的校验

    一.安装配置Openresty 1,安装 wget https://openresty.org/download/ngx_openresty-1.9.7.1.tar.gz # 下载 tar xzvf ...

  5. 死磕Spring之IoC篇 - Bean 的创建过程

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

  6. 写了一个vue+antdv的后台管理模板

    1,项目简介 写在前面===>这是一个vue+antdv的后台管理模板 项目地址: https://github.com/BaiFangZi/vue-antd-manage 1.1,概述 ​ 最 ...

  7. MySQL:安装与配置

    记录一次 MySQL 在Windows系统的安装配置过程 安装MySQL 0.下载社区版安装包 官网下载地址:https://dev.mysql.com/downloads/installer/ 1. ...

  8. 检查字符串是否包含另一串字符串(c++)

    在c++中检查字符串是否包含另一串字符串,这个本来是我做过的一个算法题,不过最近刚好有个需求让我想到了这个题,就在此记录一下! 使用std::string::findfunction string s ...

  9. Typora For Markdown 语法

    数学表达式 要启用这个功能,首先到Preference->Editor中启用.然后使用$符号包裹Tex命令,例如:$lim_{x \to \infty} \ exp(-x)=0$将产生如下的数学 ...

  10. 【资源下载】Linux下的Hi3861一站式鸿蒙开发烧录(附工具)

    下载附件 2021春节前夕,华为发布了 HUAWEI DevEco Device Tool 2.0 Beta1,整体提供了异常强大的功能.得知消息后,我在第一时间带着无比兴奋的心情下载尝鲜,但结果却是 ...