Это плохой дизайн, чтобы ссылаться на Autofac в моих проектах только для Owned <T>? - PullRequest
10 голосов
/ 26 марта 2011

Недавно я стал активным пользователем функции Autofac OwnedInstances. Например, я использую его для предоставления фабрики для создания Unit Work для моей базы данных, что означает, что мои классы, которые зависят от фабрики UnitOfWork, запрашивают объекты типа:

Func<Owned<IUnitOfWork>>

Это невероятно полезно - отлично подходит для сохранения IDisposable вне моих интерфейсов - но это имеет свою цену: поскольку Owned <> является частью сборки Autofac, я должен ссылаться на Autofac в каждом из моих проектов, которые знают о Owned <>, и помещают «using Autofac.Features.OwnedInstances» в каждый файл кода.

Func <> имеет большое преимущество, будучи встроенным в .NET Framework, поэтому я не сомневаюсь, что можно использовать Func в качестве универсальной фабричной оболочки. Но Owned <> находится в сборке Autofac, и каждый раз, когда я его использую, я создаю жесткую ссылку на Autofac (даже когда моя единственная ссылка на Autofac - это тип Owned <> в аргументе метода интерфейса).

Мой вопрос: это плохо? Начнёт ли это укусить меня так, что я еще не учту? Иногда у меня будет проект, на который ссылаются многие другие проекты, и поэтому, естественно, мне нужно поддерживать его зависимости как можно ближе к нулю; я делаю зло, передавая Func > (который фактически является поставщиком транзакций базы данных) в методы в этих интерфейсах (которые иначе были бы независимы от автофака)?

Возможно, если Owned <> был встроенным типом .NET, вся эта дилемма исчезла бы? (Должен ли я даже задержать дыхание, чтобы это произошло?)

Ответы [ 4 ]

11 голосов
/ 27 марта 2011

Я согласен с @ steinar , я бы посчитал Autofac еще одной сторонней DLL, поддерживающей ваш проект. Ваша система зависит от этого, почему вы должны ограничивать себя от ссылки на него? Я был бы более осторожен, если бы ILifetimeScope или IComponentContext были разбросаны вокруг вашего кода.

Тем не менее, я чувствую вашу заботу. В конце концов, 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-контейнером, при таком подходе будет гораздо меньше трений.

10 голосов
/ 26 марта 2011

Я бы сказал, что хорошо ссылаться на четко определенный набор основных сторонних библиотек DLL в каждом проекте решения «корпоративного приложения» (или любого приложения, которому требуется гибкость).Я не вижу ничего плохого в том, чтобы иметь зависимость по крайней мере от следующего в каждом проекте, который нуждается в этом:

  • Среда ведения журналов (например, log4net)
  • Некоторый контейнер IoC (например, Autofac)

Тот факт, что они не являются частью ядра .NET Framework, не должен мешать нам использовать их как либерально.

Единственные возможные недостатки, которые я вижу, относительно незначительны по сравнениюк возможным преимуществам:

  • Это может усложнить понимание приложения для среднего программиста
  • В будущем у вас могут возникнуть проблемы с совместимостью версий, с которыми вы бы не столкнулись, если быпросто используя .NET Framework
  • Существуют очевидные, но незначительные накладные расходы при добавлении всех этих ссылок к каждому решению
3 голосов
/ 12 мая 2016

Я не думаю, что ссылка на сборку Autofac является реальной проблемой - я считаю, что такие вещи, как Owned, появляются в коде приложения как «запах кода». Код приложения не должен заботиться о том, какая структура DI используется, и наличие Owned в вашем коде теперь создает жесткую зависимость от Autofac. Весь код, связанный с DI, должен содержаться в наборе классов конфигурации (Модули в мире Autofac).

3 голосов
/ 28 марта 2011

Возможно, если Owned <> был встроенным .NET типа, вся эта дилемма пошла бы далеко? (Должен ли я даже задержать дыхание чтобы это случилось?)

Это будет встроенный тип .NET: ExportLifeTimeContext<T>. Несмотря на название, этот класс на самом деле не связан с .NET ExportFactory<T>. Конструктор просто принимает значение и Action для вызова при удалении времени жизни этого значения.

Пока что он доступен только в Silverlight. Для обычной платформы .NET вам придется подождать до .NET 4.x (или любой другой версии после 4.0).

...