C# 使用ActivatorUtilities确定在运行时注入哪个实现

C# 使用ActivatorUtilities确定在运行时注入哪个实现,c#,.net-core,ioc-container,C#,.net Core,Ioc Container,我正在使用内置的.Net核心IoC容器来解决应用程序的依赖关系。使用Scrutor扫描我的程序集时,我的配置方式如下: services.Scan(s => s .FromAssembliesOf(currentAssemblyTypesList) .AddClasses(false) .UsingRegistrationStrategy(RegistrationStrategy.Append) .AsImplementedInterfaces()

我正在使用内置的.Net核心IoC容器来解决应用程序的依赖关系。使用Scrutor扫描我的程序集时,我的配置方式如下:

services.Scan(s => s
    .FromAssembliesOf(currentAssemblyTypesList)
    .AddClasses(false)
    .UsingRegistrationStrategy(RegistrationStrategy.Append)
    .AsImplementedInterfaces()
    .WithTransientLifetime());
到目前为止,我已经有过一些简单的例子,其中每个接口都由一个依赖项实现,因此前面的配置可以完美地解析整个依赖项树

现在考虑下面的代码:

public interface IService {}  

public class ServiceOne : IService 
{
     public ServiceOne(IDependency dependency) {}
}  

public class ServiceTwo : IService 
{
     public ServiceTwo(IDependency dependency) {}
}  

public class SomeClass  
{  
    public SomeClass(IService service) {}  

    public void DoSomething()
    {
        this.service.SomeMethod();
    }
}
Func<IServiceProvider, object> factoryMethod = sp =>
{
    if (condition1 && condition2)
    {
        return ActivatorUtilities.CreateInstance<ServiceOne>(sp);
    }
    else
    {
        return ActivatorUtilities.CreateInstance<ServiceTwo>(sp);
    }
};

services.Replace(ServiceDescriptor.Describe(typeof(IService), factoryMethod, ServiceLifetime.Transient));

在这种情况下,“MeCuCLAS”位于一个依赖树的中间,并且我有两个服务实现相同的接口,其中一个应该被注入到“MeCasCases”中,直到运行时才知道。出于不重要的原因,我被要求为此使用ActivatorUtilities类

我正在处理两种场景来确定应该实例化哪个iSeries设备:

  • 在应用程序启动时,将设置一个标志,用于确定在注册之前要使用的服务(对于类似的设置,但不针对相同的依赖关系树)
  • 在执行“DoSomething”方法的过程中,会决定使用这两个服务中的哪一个,所以我猜应该注册某种工厂并将其注入“SomeClass”
  • 因此,问题是我需要更改或添加什么到依赖项注册过程中,以及如何使用ActivatorUtilities类来实现这些目标


    谢谢。

    不太清楚你想要达到什么目标,但我认为是这样的

    services.AddTransient<IService>(sp =>
    {
        if (condition1 && condition2)
            ActivatorUtilities.CreateInstance<ServiceOne>(sp);
        else
            ActivatorUtilities.CreateInstance<ServiceTwo>(sp);
    });
    
    services.AddTransient(sp=>
    {
    如果(条件1和条件2)
    ActivatorUtilities.CreateInstance(sp);
    其他的
    ActivatorUtilities.CreateInstance(sp);
    });
    
    不太清楚你想要实现什么,但我认为是这样的

    services.AddTransient<IService>(sp =>
    {
        if (condition1 && condition2)
            ActivatorUtilities.CreateInstance<ServiceOne>(sp);
        else
            ActivatorUtilities.CreateInstance<ServiceTwo>(sp);
    });
    
    services.AddTransient(sp=>
    {
    如果(条件1和条件2)
    ActivatorUtilities.CreateInstance(sp);
    其他的
    ActivatorUtilities.CreateInstance(sp);
    });
    
    因此,最棘手的部分是,当注册已经发生,并且有一种方法可以替换特定的定义时,如何处理第一个场景。这可以通过以下代码实现:

    public interface IService {}  
    
    public class ServiceOne : IService 
    {
         public ServiceOne(IDependency dependency) {}
    }  
    
    public class ServiceTwo : IService 
    {
         public ServiceTwo(IDependency dependency) {}
    }  
    
    public class SomeClass  
    {  
        public SomeClass(IService service) {}  
    
        public void DoSomething()
        {
            this.service.SomeMethod();
        }
    }
    
    Func<IServiceProvider, object> factoryMethod = sp =>
    {
        if (condition1 && condition2)
        {
            return ActivatorUtilities.CreateInstance<ServiceOne>(sp);
        }
        else
        {
            return ActivatorUtilities.CreateInstance<ServiceTwo>(sp);
        }
    };
    
    services.Replace(ServiceDescriptor.Describe(typeof(IService), factoryMethod, ServiceLifetime.Transient));
    
    Func factoryMethod=sp=>
    {
    如果(条件1和条件2)
    {
    返回ActivatorUtilities.CreateInstance(sp);
    }
    其他的
    {
    返回ActivatorUtilities.CreateInstance(sp);
    }
    };
    Replace(servicescriptor.descripe(typeof(IService)、factoryMethod、ServiceLifetime.Transient));
    
    如果在依赖项注册时,即在发出任何请求之前启动应用程序时,已知条件1和条件2,则此功能非常有效

    对于另一种情况,在应用程序运行并发出请求之前,条件是未知的,因为内置的.Net Core IoC容器的功能不如Castle或Autofac等其他容器丰富。一种方法是手动创建factory方法对象,如下所示:

    public interface IServiceFactory
    {
        IService Get(MyObject myObject);
    }
    
    public class ServiceFactory : IServiceFactory
    {
        private readonly IServiceProvider sp;
    
        public ServiceFactory(IServiceProvider sp)
        {
            this.sp = sp;
        }
    
        public IService Get(MyObject myObject)
        {
            if(myObject.SomeProperty == "whatever")
            {
                return ActivatorUtilities.CreateInstance<ServiceOne>(this.sp);
            }
            else
            {           
                return ActivatorUtilities.CreateInstance<ServiceTwo>(this.sp);
            }
        }
    }
    
    公共接口IServiceFactory
    {
    IService Get(MyObject MyObject);
    }
    公共类服务工厂:IServiceFactory
    {
    专用只读阅读器ViceProvider sp;
    公共服务工厂(IServiceProvider sp)
    {
    这个.sp=sp;
    }
    公共IService Get(MyObject MyObject)
    {
    if(myObject.SomeProperty==“无论什么”)
    {
    返回ActivatorUtilities.CreateInstance(this.sp);
    }
    其他的
    {           
    返回ActivatorUtilities.CreateInstance(this.sp);
    }
    }
    }
    
    这里要记住的唯一一点是,接口可以而且应该在定义所有其他应用程序接口的地方定义,由于使用了IServiceProvider接口,您不希望应用程序的其余部分与MicrosoftExtensions.DependencyInjection包紧密耦合,因此工厂的实现应该在定义其余注册逻辑的任何地方


    我非常努力地寻找ActivatorUtilities.CreateFactory方法的一个示例,该方法会给出类似的结果,但找不到。我希望这对某些人有用。

    所以最棘手的部分是,当注册已经发生,并且有一种方法可以替换特定的定义时,如何处理第一个场景。这可以通过以下代码实现:

    public interface IService {}  
    
    public class ServiceOne : IService 
    {
         public ServiceOne(IDependency dependency) {}
    }  
    
    public class ServiceTwo : IService 
    {
         public ServiceTwo(IDependency dependency) {}
    }  
    
    public class SomeClass  
    {  
        public SomeClass(IService service) {}  
    
        public void DoSomething()
        {
            this.service.SomeMethod();
        }
    }
    
    Func<IServiceProvider, object> factoryMethod = sp =>
    {
        if (condition1 && condition2)
        {
            return ActivatorUtilities.CreateInstance<ServiceOne>(sp);
        }
        else
        {
            return ActivatorUtilities.CreateInstance<ServiceTwo>(sp);
        }
    };
    
    services.Replace(ServiceDescriptor.Describe(typeof(IService), factoryMethod, ServiceLifetime.Transient));
    
    Func factoryMethod=sp=>
    {
    如果(条件1和条件2)
    {
    返回ActivatorUtilities.CreateInstance(sp);
    }
    其他的
    {
    返回ActivatorUtilities.CreateInstance(sp);
    }
    };
    Replace(servicescriptor.descripe(typeof(IService)、factoryMethod、ServiceLifetime.Transient));
    
    如果在依赖项注册时,即在发出任何请求之前启动应用程序时,已知条件1和条件2,则此功能非常有效

    对于另一种情况,在应用程序运行并发出请求之前,条件是未知的,因为内置的.Net Core IoC容器的功能不如Castle或Autofac等其他容器丰富。一种方法是手动创建factory方法对象,如下所示:

    public interface IServiceFactory
    {
        IService Get(MyObject myObject);
    }
    
    public class ServiceFactory : IServiceFactory
    {
        private readonly IServiceProvider sp;
    
        public ServiceFactory(IServiceProvider sp)
        {
            this.sp = sp;
        }
    
        public IService Get(MyObject myObject)
        {
            if(myObject.SomeProperty == "whatever")
            {
                return ActivatorUtilities.CreateInstance<ServiceOne>(this.sp);
            }
            else
            {           
                return ActivatorUtilities.CreateInstance<ServiceTwo>(this.sp);
            }
        }
    }
    
    公共接口IServiceFactory
    {
    IService Get(MyObject MyObject);
    }
    公共类服务工厂:IServiceFactory
    {
    专用只读阅读器ViceProvider sp;
    公共服务工厂(IServiceProvider sp)
    {
    这个.sp=sp;
    }
    公共IService Get(MyObject MyObject)
    {
    if(myObject.SomeProperty==“无论什么”)
    {
    返回ActivatorUtilities.CreateInstance(this.sp);
    }
    其他的
    {