使用Autofac注册容器本身

时间:2016-04-24 03:36:56

标签: c# inversion-of-control autofac ioc-container

我想知道注册容器本身是否有任何副作用

IContainer container;
ContainerBuilder builder = new ContainerBuilder();
container = builder.Build();
builder.RegisterInstance(container).As<IContainer>();

并像这样使用它

builder.RegisterType<IManagmentServiceImp>().As<ManagmentServiceImp>()
    .WithParameter(new ResolvedParameter(
            (pi, ctx) => pi.ParameterType == typeof(IContainer) && pi.Name == "Container",
            (pi, ctx) => container
));

或者它是否会起作用。

4 个答案:

答案 0 :(得分:24)

您的代码不安全,因为您在初始化之前注册了一个实例。

如果您需要访问组件内的容器(这不是一个好主意),您可以依赖具有import ftplib import socket import ssl class FTP(ftplib.FTP): def getline(self): line = self.file.readline(self.maxline + 1).decode("utf-8") if len(line) > self.maxline: raise ftplib.Error("got more than %d bytes" % self.maxline) if self.debugging > 1: print('*get*', self.sanitize(line)) if not line: raise EOFError if line[-2:] == ftplib.CRLF: line = line[:-2] elif line[-1:] in ftplib.CRLF: line = line[:-1] return line class FTPS(ftplib.FTP_TLS): def __init__(self, host='', user='', passwd='', acct='', keyfile=None, certfile=None, timeout=60): ftplib.FTP_TLS.__init__(self, host=host, user=user, passwd=passwd, acct=acct, keyfile=keyfile, certfile=certfile, timeout=timeout) def connect(self, host='', port=0, timeout=-999, source_address=None): if host != '': self.host = host if port > 0: self.port = port if timeout != -999: self.timeout = timeout try: self.sock = socket.create_connection((self.host, self.port), self.timeout) self.af = self.sock.family self.sock = ssl.wrap_socket(self.sock, self.keyfile, self.certfile, ssl_version=ssl.PROTOCOL_TLSv1_2) self.file = self.sock.makefile('rb') self.welcome = self.getresp() except Exception as e: print(e) return self.welcome if __name__ == "__main__": ftps = FTPS() ftps.connect("host", 990) # Returns b'welcomemessage' ftps.login("user", "pwd") ftps.prot_p() ftps.close() 方法的ILifetimeScope

Resolve

public class ManagmentServiceImp { public ManagmentServiceImp(ILifetimeScope scope) { } } 会自动在 Autofac 中注册,您无需为其添加注册。

有关详细信息,请参阅 Autofac 文档中的Controlling Scope and Lifetime

顺便说一句,依赖IoC容器并不是一个好习惯。看起来你使用Service Locator反模式。如果您需要容器延迟加载依赖项,则可以将合成与ILifetimeScopeFunc<T>

一起使用
Lazy<T>

在这种情况下,首次访问时会创建public class ManagmentServiceImp { public ManagmentServiceImp(Lazy<MyService> myService) { this._myService = myService; } private readonly Lazy<MyService> _myService; }

有关详细信息,请参阅 Autofac 文档中的Implicit Relationship

答案 1 :(得分:10)

您可以使用此扩展方法:

public static void RegisterSelf(this ContainerBuilder builder)
{
    IContainer container = null;
    builder.Register(c => container).AsSelf();
    builder.RegisterBuildCallback(c => container = c);
}

像这样使用它:builder.RegisterSelf();

答案 2 :(得分:2)

由于您需要向builder.RegisterInstance()提供容器的实例,因此您需要在将其作为参数传递之前对其进行初始化,而您当前没有这样做。但是,如果构建容器构建器以构建AFTER注册(和容器初始化),则可以成功解析类中的容器实例。

请注意,这肯定是依赖注入中的设计气味,你绝对不应该这样做。您的容器/内核应该只存在于对象图的顶层。如果你开始注入你的容器,你几乎肯定会去服务定位器反模式。

void Main()
{
    IContainer container = new ContainerBuilder().Build();
    ContainerBuilder builder = new ContainerBuilder();

    builder.RegisterInstance(container).As<IContainer>();

    builder.RegisterType<ManagementServiceImp>().As<IManagmentServiceImp>()
       .WithParameter(new ResolvedParameter(
            (pi, ctx) => pi.ParameterType == typeof(IContainer) && pi.Name == "Container",
            (pi, ctx) => container
    ));

    container = builder.Build();
    var instance = container.Resolve<IManagmentServiceImp>();
}

public class ManagementServiceImp : IManagmentServiceImp 
{ 
    private IContainer _container;

    public ManagementServiceImp(IContainer Container)
    {
        _container = Container;
        _container.Dump();
    }
}

public interface IManagmentServiceImp { }

答案 3 :(得分:-2)

虽然我没有回答你的问题。尝试在服务类中获取容器的句柄或者除了相当于IModule之外的任何东西都是代码味道。

您的服务代码不应该了解IOC IMO。