在我的项目中仅为Owned <t>?</t>引用Autofac是不好的设计

时间:2011-03-25 21:23:06

标签: c# idisposable autofac

我最近成为了Autofac的OwnedInstances功能的重要用户。例如,我用它来提供一个工厂来为我的数据库创建一个工作单元,这意味着我依赖于UnitOfWork工厂的类要求输入类型的对象:

Func<Owned<IUnitOfWork>>

这非常有用 - 非常适合keeping IDisposable out of my interfaces - 但它带有价格:自拥有&lt;&gt;是Autofac程序集的一部分,我必须在每个知道Owned&lt;&gt;的项目中引用Autofac,并在每个代码文件中放置“使用Autofac.Features.OwnedInstances”。

函数功能&LT;&GT;具有内置于.NET框架的巨大好处,因此我毫不怀疑将Func用作通用工厂包装器是可以的。但是拥有&lt;&gt;在Autofac程序集中,每次我使用它时,我都会创建一个对Autofac的硬引用(即使我在接口方法参数中对Autofac的唯一引用是Owned&lt;&gt;类型)。

我的问题是:这是件坏事吗?这会开始以某种方式让我回头,我还没有考虑到这一点吗?有时我会有一个由许多其他项目引用的项目,因此我自然需要将其依赖关系尽可能接近零;我通过传递Func&lt; Owned&lt; IUnitOfWork&gt;&gt;做恶(这实际上是一个数据库事务提供者)进入这些接口中的方法(否则将是autofacnnostic)?

也许如果拥有&lt;&gt;是一个内置的.NET类型,这整个困境会消失吗? (我是否应该屏住呼吸才能实现?)

4 个答案:

答案 0 :(得分:11)

我同意@steinar,我会认为Autofac是另一个支持您项目的第三方dll。您的系统依赖于它,为什么要限制自己参考它?如果在您的代码周围散布ILifetimeScopeIComponentContext,我会更加关注。

那就是说,我感受到了你的安慰。毕竟,DI容器应该在幕后工作,而不是“溢出”到代码中。但是我们可以轻松地创建一个包装器和一个界面来隐藏Owned<T>。请考虑以下界面和实现:

public interface IOwned<out T> : IDisposable
{
    T Value { get; }
}

public class OwnedWrapper<T> : Disposable, IOwned<T>
{
    private readonly Owned<T> _ownedValue;

    public OwnedWrapper(Owned<T> ownedValue)
    {
        _ownedValue = ownedValue;
    }

    public T Value { get { return _ownedValue.Value; } }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
            _ownedValue.Dispose();
    }
}

可以使用注册源或构建者进行注册,例如像这样:

var cb = new ContainerBuilder();
cb.RegisterGeneric(typeof (OwnedWrapper<>)).As(typeof (IOwned<>)).ExternallyOwned();
cb.RegisterType<SomeService>();
var c = cb.Build();

您现在可以照常解决:

using (var myOwned = c.Resolve<IOwned<SomeService>>())
{
    var service = myOwned.Value;       
}

您可以将此界面放在系统中的公共命名空间中,以便于包含。 Owned<T>OwnedWrapper<T>现在都隐藏在您的代码中,只显示IOwned<T>。如果需求发生变化,您需要将Autofac替换为另一个DI容器,那么这种方法的摩擦力就会大大降低。

答案 1 :(得分:10)

我想说,在“企业应用程序”解决方案(或任何需要灵活性的应用程序)的每个项目中引用一组定义明确的核心第三方DLL都没关系。我认为在每个需要它的项目中至少依赖以下内容没有错:

  • 日志框架(例如log4net)
  • 某些IoC容器(例如Autofac)

这些不是核心.NET框架的一部分这一事实不应该阻止我们自由地使用它们。

与可能的好处相比,我能看到的唯一可能的负面影响相对较小:

  • 这可能会使普通程序员更难理解应用程序
  • 如果您只是使用.NET框架
  • ,将来可能会出现版本兼容性问题
  • 将所有这些引用添加到每个解决方案中都有明显但很小的开销

答案 2 :(得分:3)

  

也许如果拥有&lt;&gt;是一个内置的.NET   类型,这整个进退两难的局面   远? (我应该屏住呼吸   要发生这种情况?)

它将成为内置的.NET类型:ExportLifeTimeContext<T>。尽管有这个名字,但这个类并没有真正绑定到.NET ExportFactory<T>。构造函数只接受一个值,并在释放该值的生命周期时调用Action

目前,它仅适用于Silverlight。对于常规.NET框架,您必须等到.NET 4.x(或4.0之后的下一个版本)。

答案 3 :(得分:3)

我不认为引用Autofac程序集是真正的问题 - 我认为应用程序代码中出现Owned之类的问题&#39;代码气味&#39;。应用程序代码不应该关心正在使用的DI框架,并且在代码中使用Owned现在会对Autofac产生硬依赖。所有与DI相关的代码都应该干净地包含在一组配置类中(Autofac世界中的模块)。