2010-05-23 3 views
1

Представьте себе:Одноразовый реестр: хороший шаблон?

public class Global : IDisposable 
{ 
    private static readonly List<IDisposable> Disposables = new List<IDisposable>(); 

    public void ApplicationStart() 
    { 
     var heavyLifter = new HeavyLifter(); 
     Disposables.Add(heavyLifter); 
      // register a few more 
    } 

    public void Dispose() 
    { 
     Disposables.ForEach(d => d.Dispose()); 
    } 
} 

Я несколько неопытных с IDisposable. Является ли это жизнеспособным образцом?

+0

Что вы пытаетесь сделать с этим? – dtb

+0

Я хочу зарегистрироваться для удаления на создание ресурса и не забудьте сделать это в другом месте на расстоянии 100 строк. Я думаю, что больше не подходит для рефакторинга, чтобы не разбрызгивать фрагменты кода во всех классах. Моя неопределенность заключается в том, что возможны проблемы, которые могут привести к утечкам памяти, проблемам потокобезопасности и т. Д. – Jan

+0

IDisposable должен помочь вам решить эти проблемы, а не создавать новые. Если вы сделаете свои методы удаления потоком безопасными и очистите все неуправляемые ресурсы, которые хранятся в каждом отдельном объекте, реализующем dispose, я думаю, что у вас будет идеальная ситуация. –

ответ

0

Возможно, этот подход имеет смысл, если вы не можете избавиться от потокобезопасности (например, при разговоре с объектами COM, которые ДОЛЖНЫ быть выпущены в том же потоке). Однако на практике вы обнаружите, что этот подход приводит к тому, что объекты живут дольше, чем нужно.

Я бы стремился сделать поток отходов безопасным, таким образом вы можете позвонить Dispose из финализатора и добиться поистине автоматического управления жизненным циклом. Вы должны быть осторожны, поскольку это не подходит для некоторых типов ресурсов - например, файлов или сетевых ручек, для которых может потребоваться более жесткий контроль. В противном случае это наилучшим образом решение этой проблемы.

Если распоряжение должно быть на одной и той же резьбе, то вы находитесь в немного рассола. Если объект, нуждающийся в утилизации, находится на уровне модели (как и в объекте бизнес-правил) - вполне вероятно, что на нем есть слои пользовательского интерфейса, требующие сложной логики для его удаления (например, события после закрытия окна).Это потерянная/потерянная ситуация и выбор между объектами, живущими вечно (например, ваше оригинальное решение) и сложной логикой утилизации (которая становится довольно уродливой довольно быстро).

Возможно, что-то экспериментировать с. Вы можете отделить одноразовый ресурс в своем собственном классе, и на его фабрике будет содержаться ссылка на него. Объект ресурса сохраняет слабую ссылку на бизнес-объект. Когда бизнес-объект будет завершен, WeakReference вернет null, что позволит вам пройти через одноразовые предметы и сбросить те, которые больше не нужны.

public class Global { 
    private static readonly List<Resource> Disposables = new List<Resource>(); 

    public HeavyLifter GetHeavyLifter() 
    { 
     var resource = new HeavyLifterResource(); 
     var heavyLifter = new HeavyLifter(resource); 
     resource.BusinessObject = heavyLifter; 
     Disposables.Add(resource); 
    } 

    public void DisposeAll() 
    { 
     Disposables.ForEach(d => d.CleanUp()); 
    } 
} 

public abstract class Resource : IDisposable { 

    WeakReference<object> m_BusinessObject; 
    public WeakReference<object> BusinessObject {get;set;} 

    public CleanUp() { 
     if (!m_BusinessObject.IsAlive) 
     Dispose(); 
    } 
} 

public HeavyLifter { 
    public HeavyLifter (Disposable d) { 
     m_resourceObj = d; 
    } 

    HeavyLifterResource m_resourceObj; 
} 

public class HeavyLifterResource :Resource { 
    public void Dispose() { 
     //disposal 
    } 
} 

Позвольте мне еще раз повторить, что приведенный выше подход подходит только для определенного класса объектов. Вы не хотите обрабатывать сетевые подключения таким нечетким образом, но вы можете, например, сделать это для бизнес-объектов, которым требуется сетевое подключение, чтобы распоряжаться собой. Даже тогда это подходит только тогда, когда такое соединение является постоянным в течение всего срока службы приложения.

0

Ваш код подразумевает, что HeavyLifter реализует IDisposable. Итак, все, что вам нужно сделать, это вызвать его метод Dispose в обработчике событий Application_End.

3

Из чего я понимаю, вы создаете компонент, который будет использовать (я предполагаю) несколько ресурсов, которые реализуют IDisposable, и вы просто ищете способ сохранить список объектов IDisposable в своем компоненте и просто перебрать над списком, а не с вызовом Dispose по каждому элементу по имени, это правильно?

Если это так, в этом нет ничего плохого. Однако ваш список не должен быть static, он должен быть экземпляром.

+0

Когда я увидел это, я сразу же подумал о базовом классе с защищенными членами. – Joshua

1

Ну на один уровень контейнеров МОК, таких как единство может предложить именно такую ​​функциональность:

http://msdn.microsoft.com/en-us/library/ff663144.aspx

Вы делегировать ответственность за создание объектов в контейнер МОК, и может указать параметр LifetimeMangement. Это может включать регистрацию в контейнере для последующего удаления, например. вызов утилизации на контейнере, когда приложение закрывается, или когда форма закрыта.

Для объектов с коротким замыканием вы, вероятно, захотите управлять самим собой, но для более долговечных объектов шаблон репозитория типа IOC с удалением объекта может работать очень хорошо. Хорошо работает для меня. :)

Хорошее понимание утилизации всегда является хорошей вещью.

+0

Да, конечно, контейнер будет делать что-то подобное, но на самом деле я не регистрирую здесь компоненты, к которым я буду обращаться позже. Это приложения, которые будут жить на своем собственном потоке, делая свое дело в течение всего срока службы приложения. Фактически каждый из них может иметь свой собственный контейнер :) – Jan

+0

Unity довольно сложный и, кажется, предлагает что-то, что будет делать именно то, что вы пытаетесь сделать. Вы можете создавать дочерние контейнеры, а также знать о потоках ... –

+0

Unity предоставляет опции для создания дочерних контейнеров и PerThreadLifetimeManager, которые могут представлять интерес: http://msdn.microsoft.com/en-us/library/microsoft.practices. unity.perthreadlifetimemanager.aspx – dotnetguy

1

Вы работаете в предположении, что внешний класс будет иметь специальное знание времени жизни объекта, чтобы он вызывал Dispose() в нужное время. Это редко работает, только код клиента знает, когда это делается с объектом.

С вашим классом, как написано, вы достигаете абсолютно противоположной цели, вы сохраните объекты живыми дольше, чем необходимо. Даже сборщик мусора не смог запустить финализатор, потому что вы держитесь за объект до некоторого волшебного момента времени, когда все объекты готовы к удалению. Обычным термином для этого является «утечка памяти». Не делай этого.

0

Реестр удаления иногда может быть полезен как конкретный тип, в тех случаях, когда известно, что объект, который создается, будет иметь срок службы, привязанный к другому объекту. Если класс разработан таким образом, что его создание может иметь место только обернутое в пределах конкретного способа фабрики, и если один не возражает против использования ThreadStatic переменных, один может даже быть в состоянии заменить:

DisposableThing Foo; // At one point in the class 
... 
Foo = new DisposableThing(); // In the constructor 
... 
DisposableThing.Dispose; // In `Dispose(bool)` 

с

DisposableThing = DisposeProtector.Register(new DisposableThing()); 

Уход за декларацией, инициализацией и очисткой, все в одной строке.

Очень хороший чистый шаблон и тот, который еще лучше в vb.net (нет обязательных переменных ThreadStatic, а метод регистрации регистрации может быть членом базового типа). Наверное, слишком скучно, чтобы стоить на C#, но в vb.net это может быть хороший шаблон. Обратите внимание, что если конструктор правильно упакован, Dispose будет вызываться во всем, что было зарегистрировано в его области видимости [но не вложенной области], когда в классе вызывается Dispose, или конструктор выбрасывает, причем последний является ситуацией, когда в противном случае трудно избежать утечек.

Смежные вопросы