IUsable: управление ресурсами лучше, чем IDisposable - PullRequest
1 голос
/ 21 октября 2008

Хотелось бы, чтобы у нас был шаблон "Usable" в C #, когда блок кода с использованием конструкции передавался бы функции в качестве делегата:

class Usable : IUsable
{
  public void Use(Action action)  // implements IUsable
  {
    // acquire resources
     action();
    // release resources
  }
}

и в коде пользователя:

using (new Usable())
{
  // this code block is converted to delegate and passed to Use method above
}

Плюсы:

  • Контролируемое выполнение, исключения
  • Факт использования "Usable" виден в стеке вызовов

Минусы:

  • Стоимость делегата

Как вы думаете, это выполнимо и полезно, и если у него нет проблем с языковой точки зрения? Есть ли какие-либо подводные камни, которые вы можете увидеть?

РЕДАКТИРОВАТЬ: Дэвид Шмитт предложил следующие

using(new Usable(delegate() {
    // actions here
}) {}

Он может работать в этом примере, но обычно у вас уже есть выделенный ресурс, и вы хотите, чтобы он выглядел следующим образом:

using (Repository.GlobalResource) 
{ 
  // actions here 
}

Где GlobalResource (да, я знаю, что глобальные ресурсы плохие) реализует IUsable. Вы можете переписать так коротко, как

Repository.GlobalResource.Use(() =>
{
  // actions here
});

Но это выглядит немного странно (и более странно, если вы реализуете интерфейс явно), и это так часто встречается в различных вариантах, что я подумал, что он заслуживает того, чтобы быть новым синтаксическим сахаром в языке.

Ответы [ 3 ]

3 голосов
/ 21 октября 2008

ИМХО, я не вижу большого смысла в этом паттерне, потому что:

  1. использование блока уже требует, чтобы объект имел интерфейс IDisposable, поэтому мы можем использовать интерфейс IDisposable для контролируемого выполнения
  2. Откуда мы здесь передаем объект Action?

Я уже успешно использовал этот тип шаблона для действий с базой данных с использованием IDisposable.

2 голосов
/ 21 октября 2008

А как же:

class Usable<T> where T : ICriticalResource, new()
{
    static void Do(Action<T> action) {
        ICriticalResource resource = new T();
        resource.Acquire();
        action(resource);
        resource.Relese();
    }
}

Затем вы используете его для всего, что реализует ICritialResource.

Usable<SomeResource>.Do(resource => resource.SomeMethod());

Другой вариант - использовать IDisposable таким, какой он есть. Да, это может быть не так элегантно, как могло бы быть, но по крайней мере большинство людей привыкли к этому.

1 голос
/ 21 октября 2008

Вы можете получить большую часть этого, используя анонимный делегат, подобный этому:

using(new Usable(delegate() {
    // actions here
}) {}

Конечно, оборачивая это в какую-то функцию или непосредственно реализуя try / finally, можно сделать это не только полезным, но даже немного привлекательным.

...