在我的项目中仅针对 Owned 引用 Autofac 是不是不好的设计?

发布于 2024-10-26 21:33:47 字数 907 浏览 5 评论 0 原文

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

Func<Owned<IUnitOfWork>>

这非常有用 - 非常适合 将 IDisposable 排除在我的界面之外- -但它是有代价的:自从拥有>>是 Autofac 程序集的一部分,我必须在每个了解 Owned<> 的项目中引用 Autofac,并将“using Autofac.Features.OwnedInstances”放入每个代码文件中。

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

我的问题是:这是一件坏事吗?这是否会以某种我尚未考虑到的方式开始反噬我?有时我会有一个被许多其他项目引用的项目,所以自然地我需要保持它的依赖关系尽可能接近零;我是否通过传递 Func> 来作恶? (实际上是一个数据库事务提供者)到这些接口中的方法(否则将与 autofac 无关)?

也许如果拥有<>如果是内置的 .NET 类型,那么整个困境就会消失吗? (我什至应该屏住呼吸才能发生这种情况吗?)

I've recently become a heavy user of Autofac's OwnedInstances feature. For example, I use it to provide a factory for creating a Unit of Work for my database, which means my classes which depend on the UnitOfWork factory are asking for objects of type :

Func<Owned<IUnitOfWork>>

This is incredibly useful--great for keeping IDisposable out of my interfaces--but it comes with a price: since Owned<> is part of the Autofac assembly, I have to reference Autofac in each of my projects that knows about Owned<>, and put "using Autofac.Features.OwnedInstances" in every code file.

Func<> has the great benefit of being built into the .NET framework, so I have no doubts that it's fine to use Func as a universal factory wrapper. But Owned<> is in the Autofac assembly, and every time I use it I'm creating a hard reference to Autofac (even when my only reference to Autofac is an Owned<> type in an interface method argument).

My question is: is this a bad thing? Will this start to bite me back in some way that I'm not yet taking into account? Sometimes I'll have a project which is referenced by many other projects, and so naturally I need to keep its dependencies as close as possible to zero; am I doing evil by passing a Func<Owned<IUnitOfWork>> (which is effectively a database transaction provider) into methods in these interfaces (which would otherwise be autofac-agnostic)?

Perhaps if Owned<> was a built-in .NET type, this whole dilemma would go away? (Should I even hold my breath for that to happen?)

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

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

发布评论

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

评论(4

彩扇题诗 2024-11-02 21:33:47

我同意 @steinar,我将 Autofac 视为另一个支持您的项目的第 3 方 dll。您的系统依赖于它,为什么您应该限制自己引用它?如果 ILifetimeScopeIComponentContext 散布在您的代码中,我会更加担心。

话虽如此,我感受到了你的担忧。毕竟,DI 容器应该在幕后工作,而不是“溢出”到代码中。但我们可以轻松创建一个包装器和一个接口来隐藏 Owned。考虑以下接口和实现:

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;       
}

您可以将此接口放置在系统中的公共命名空间中以便于包含。
OwnedOwnedWrapper 现在都对您的代码隐藏,仅公开 IOwned。如果需求发生变化并且您需要将 Autofac 替换为另一个 DI 容器,则这种方法的摩擦会少很多。

I agree with @steinar, I would consider Autofac as yet another 3rd party dll that supports your project. Your system depends on it, why should you restrict yourself from referencing it? I would be more conserned if ILifetimeScope or IComponentContext were sprinkled around your code.

That said, I feel your consern. After all, a DI container should work behind the scenes and not "spill" into the code. But we could easily create a wrapper and an interface to hide even the Owned<T>. Consider the following interface and implementation:

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();
    }
}

The registration could be done, either using a registration source or a builder, e.g. like this:

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

You can now resolve as usual:

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

You could place this interface in a common namespace in your system for easy inclusion.
Both the Owned<T> and OwnedWrapper<T> are now hidden from your code, only IOwned<T> is exposed. Should requirements change and you need to replace Autofac with another DI container there's a lot less friction with this approach.

和影子一齐双人舞 2024-11-02 21:33:47

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

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

事实上,这些不是核心 .NET 框架的一部分。不要阻止我们随意使用它们。

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

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

I would say that it's fine to reference a well defined set of core 3rd party DLLs in every project of an "enterprise application" solution (or any application that needs flexibility). I see nothing wrong with having a dependency on at least the following in every project that needs it:

  • A logging framework (e.g. log4net)
  • Some IoC container (e.g. Autofac)

The fact that these aren't part of the core .NET framework shouldn't stop us from using them as liberally.

The only possible negatives I can see are relatively minor compared to the possible benefits:

  • This may make the application harder to understand for the average programmer
  • You could have version compatibility problems in the future which you wouldn't encounter if you were just using the .NET framework
  • There is an obvious but minor overhead with adding all of these references to every solution
誰認得朕 2024-11-02 21:33:47

也许如果拥有的话<>是一个内置的.NET
类型,这整个困境就会消失
离开? (我是否应该屏住呼吸
为了实现这一点?)

它将成为内置的 .NET 类型: ExportLifeTimeContext。尽管有这个名称,此类实际上并未绑定到 .NET ExportFactory。构造函数只接受一个值和一个在该值的生命周期被释放时调用的Action

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

Perhaps if Owned<> was a built-in .NET
type, this whole dilemma would go
away? (Should I even hold my breath
for that to happen?)

It will become a built-in .NET type: ExportLifeTimeContext<T>. Despite the name, this class isn't really bound to the .NET ExportFactory<T>. The constructor simply takes a value, and an Action to invoke when the lifetime of that value is disposed.

For now, it is only available in Silverlight though. For the regular .NET framework you'll have to wait until .NET 4.x (or whatever the next version after 4.0 will be).

不爱素颜 2024-11-02 21:33:47

我不认为引用 Autofac 程序集是真正的问题 - 我认为应用程序代码中出现的诸如 Owned 之类的内容是“代码味道”。应用程序代码不应该关心正在使用什么 DI 框架,并且代码中的 Owned 现在会创建对 Autofac 的硬依赖。所有 DI 相关代码都应该干净地包含在一组配置类(Autofac 世界中的模块)中。

I don't think referencing the Autofac assembly is the real problem - I consider things like Owned appearing in application code a 'code smell'. Application code shouldn't care about what DI framework is being used and having Owned in your code now creates a hard dependency on Autofac. All DI related code should be cleanly contained in a set of configuration classes (Modules in the Autofac world).

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