关于gettig的一些问题,从autofac开始

发布于 2024-10-09 07:54:46 字数 203 浏览 4 评论 0原文

我刚刚开始掌握 Autofac,并有以下问题:

  1. 例如,当您将参数传递给构造函数时,Guice 有自己的注释/方式(它们由 Guice 处理)。 autofac 有类似的功能吗?这是在类定义中,而不是在我实例化该类时。

  2. 当我使用类并想要获取其他类型时,我是否每次都设置容器(我假设这应该是静态成员?)?

I am just getting to grips with Autofac, and have the following questions:

  1. Guice, for example, has its own annotations/ways when you pass parameters into constructors (they are handled by Guice). Does autofac do anything similar? This is in th class definition, not when I instantiate the class.

  2. When I am using classes and want to get other types, do I setup the container each time (I am assuming this should be a static member?)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

瀟灑尐姊 2024-10-16 07:54:46

1)Autofac不需要构造函数的任何特定映射。它有一个简单的规则;它将尽可能多地注入,但它必须能够解析至少一个构造函数的所有参数。如果没有 Autofac 都知道其参数类型的构造函数,您将收到运行时异常。您可以设置 Autofac 来执行构造函数或属性注入,或两者的混合。公认的最佳实践是构造函数注入几乎所有内容;使用属性注入可以为您提供一个不具有所有必要依赖项的对象,在您尝试使用需要缺少依赖项的功能之前,您不会知道这种情况发生了。如果依赖项很昂贵,必须是工厂范围的(每个请求的新实例)并且并不总是由依赖对象使用,请考虑构造函数注入将延迟初始化此依赖项的工厂方法。

2) 如何设置 IoC 容器取决于您计划如何使用它。 IoC 容器的静态或单例实例当然是众所周知的用途,但许多人说这是一种反模式,因为它会导致您陷入使用容器作为“服务定位器”的滑坡(这使您依赖于有一个 IoC 容器来解决依赖关系;这很好,但不应该是必需的)。普遍接受的模式是向容器注册所有依赖项和所有需要依赖项的对象,并且仅在对象创建的最高级别使用容器;所有其他对象都将是顶级对象的依赖项,并且可以直接解析或可以通过工厂方法生成。

我继续将我的 Autofac 容器设置为单例,因为该容器的存在基本上是为了水合应用程序主窗体的实例,它本身需要向 IoC 注册的大部分依赖项,并且无论如何都会获取其余的依赖项,所以它可以将它们传递给它将创建的对象。我可以使用 IoC 注册所有对象并使用工厂方法解析子表单,但我将用工厂方法引用替换依赖项引用,并且我可能最终将主表单上的各个方法连接为其他方法的工厂视窗。

编辑:1) 的代码示例:

public interface IDoSomething {...}
public interface IDoSomethingElse {...}

//the implementations don't have to be the same class, of course; 
//this is for simplicity
public class DoTwoThings: IDoSomething, IDoSomethingElse {...}

public class ExpensiveObject {...}

public class DependentClass
{
    public DependentClass(IDoSomething aDoer, IDoSomethingElse anotherDoer) {...}
}

public class DependsOnExpensiveObject
{
    private Func<ExpensiveObject> Factory;
    private ExpensiveObject instance;
    public DependsOnExpensiveObject(Func<ExpensiveObject> factoryMethod) 
    { Factory = factoryMethod; }

    public bool HasInstance { get{ return instance != null; } }

    public void ForceInitialize()
    {
        instance = Factory();
    }
}

...
//In your main method, or wherever
var builder = new ContainerBuilder()
builder.RegisterType<DoTwoThings>().As<IDoSomething>();
builder.Register<DependentClass>();
var container = builder.Build();

//This line of code will throw at runtime b/c IDoSomethingElse
//does not have an implementation registered with the container.
container.Resolve<DependentClass>();

//Now we'll register the other dependency; 
//dependencies can be registered and overwritten at will
builder.RegisterType<DoTwoThings>().As<IDoSomethingElse>();
builder.Update(container);

//This line will succeed now that we have a registration for IDoSomethingElse
container.Resolve<DependentClass>();

builder.RegisterType<ExpensiveClass>();
builder.RegisterType<DependsOnExpensiveClass>();
builder.Update(container);

//Autofac will provide a delegate that resolves an ExpensiveObject
var dependent = container.Resolve<DependsOnExpensiveClass>();

if(!dependent.HasInstance) //HasInstance returns false
    dependent.ForceInitialize();

Console.WriteLine(HasInstance); // True

1) Autofac does not require any specific mapping of constructors. It has one simple rule; it will inject as much as it can, but it must be able to resolve all parameters of at least one constructor. If there are no constructors with parameter types that are all known to Autofac, you'll get a runtime exception. You can set up Autofac to perform constructor or property injection, or a hybrid of both. The accepted best practice is to constructor-inject virtually everything; using property injection can give you an object that doesn't have all necessary dependencies, which you won't know has happened until you try to use the functionality requiring the missing dependency. If a dependency is expensive, must be factory-scoped (new instance for each request) and isn't always used by the dependent object, consider constructor-injecting a factory method that will lazily initialize this dependency.

2) How you set up the IoC container depends on how you plan to use it. A static or singleton instance of the IoC container is certainly a well-known use, but many say it's an anti-pattern, as it leads you down the slippery slope of using the container as a "service locator" (which makes you dependent on having an IoC container to do your dependency resolution; it's nice, but shouldn't be required). The generally-accepted pattern is to register all dependencies AND all objects needing a dependency with the container, and to only use the container at the highest level of object creation; all other objects will be a dependency of a top-level object and are either resolved as such or can be produced via factory method.

I went ahead and set my Autofac container up as a singleton, because the container basically exists to hydrate an instance of the main form of the application, which itself needs most of the dependencies registered with the IoC, and gets the rest of them anyway so it can pass them on to objects it will create. I could have registered all objects with the IoC and resolved child forms using factory methods, but I'd be replacing the dependency references with factory method references, and I would have probably ended up hooking up individual methods on the main form as factories for other windows.

EDIT: A code sample for 1):

public interface IDoSomething {...}
public interface IDoSomethingElse {...}

//the implementations don't have to be the same class, of course; 
//this is for simplicity
public class DoTwoThings: IDoSomething, IDoSomethingElse {...}

public class ExpensiveObject {...}

public class DependentClass
{
    public DependentClass(IDoSomething aDoer, IDoSomethingElse anotherDoer) {...}
}

public class DependsOnExpensiveObject
{
    private Func<ExpensiveObject> Factory;
    private ExpensiveObject instance;
    public DependsOnExpensiveObject(Func<ExpensiveObject> factoryMethod) 
    { Factory = factoryMethod; }

    public bool HasInstance { get{ return instance != null; } }

    public void ForceInitialize()
    {
        instance = Factory();
    }
}

...
//In your main method, or wherever
var builder = new ContainerBuilder()
builder.RegisterType<DoTwoThings>().As<IDoSomething>();
builder.Register<DependentClass>();
var container = builder.Build();

//This line of code will throw at runtime b/c IDoSomethingElse
//does not have an implementation registered with the container.
container.Resolve<DependentClass>();

//Now we'll register the other dependency; 
//dependencies can be registered and overwritten at will
builder.RegisterType<DoTwoThings>().As<IDoSomethingElse>();
builder.Update(container);

//This line will succeed now that we have a registration for IDoSomethingElse
container.Resolve<DependentClass>();

builder.RegisterType<ExpensiveClass>();
builder.RegisterType<DependsOnExpensiveClass>();
builder.Update(container);

//Autofac will provide a delegate that resolves an ExpensiveObject
var dependent = container.Resolve<DependsOnExpensiveClass>();

if(!dependent.HasInstance) //HasInstance returns false
    dependent.ForceInitialize();

Console.WriteLine(HasInstance); // True
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文