Как вы предотвращаете распространение IDisposable на все ваши классы?

Ваш тест фильтра -

var result = data.filter((value, i, arr) => {
  return value[0] !== arr[i][0]
});

Но arr[i] всегда будет ссылаться на текущий элемент, перебираемый через - value, поэтому, независимо от ввода, value[0] !== arr[i][0] всегда будет оценивать как [ 115]. (потому что value === arr[i], так value[0] === arr[i][0]).

Вы можете добавить value[0] к Set, и при тестировании проверить, существует ли это значение в наборе или нет:

var data = [
  ['dupeValue', { data: 123 }],
  ['dupeValue', { data: 123 }],
  ['otherValue', { data: 1111111 }],
  ['dupeValue', { data: 123 }]
]

const firstElements = new Set();
var result = data.filter(([firstElement]) => {
  const alreadyHas = firstElements.has(firstElement);
  firstElements.add(firstElement);
  return !alreadyHas;
})

console.log(result)

136
задан GrahamS 12 September 2017 в 08:41
поделиться

7 ответов

Вы не можете действительно "препятствовать тому", чтобы IDisposable распространился. Некоторые классы должны быть расположены, как AutoResetEvent, и самый эффективный путь состоит в том, чтобы выполнить в нем Dispose() метод для предотвращения издержек финализаторов. Но этот метод нужно назвать так или иначе, так же точно как в Вашем примере классы, которые инкапсулируют или содержат IDisposable, должны расположить их, таким образом, они должны быть доступными также и т.д. Единственный способ избежать его к:

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

В некоторых случаях IDisposable может быть проигнорирован, потому что он поддерживает дополнительный случай. Например, WaitHandle реализует IDisposable для поддержки именованного Взаимного исключения. Если имя не используется, Расположить метод ничего не делает. MemoryStream является другим примером, он не использует системных ресурсов, и Располагать реализацию также ничего не делает. Тщательные взгляды о том, используется ли неуправляемый ресурс или не может быть учебным. Так может исследование доступных источников для библиотек .NET или использование декомпилятора.

34
ответ дан 23 November 2019 в 23:41
поделиться

С точки зрения правильности Вы не можете предотвратить распространение IDisposable через объектные отношения, если родительский объект создает и по существу владеет дочерним объектом, который должен теперь быть доступным. FxCop корректен в этой ситуации, и родитель должен быть IDisposable.

То, что можно сделать, стараются не добавлять IDisposable к листовому классу в иерархии объектов. Это - не всегда легкая задача, но это - интересное осуществление. С логической точки зрения нет никакой причины, что ShoeLace должен быть доступным. Вместо того, чтобы добавить WaitHandle здесь, это также возможный добавить ассоциацию между ShoeLace и WaitHandle в точке, это используется. Самый простой путь через экземпляр Словаря.

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

19
ответ дан 23 November 2019 в 23:41
поделиться

Это в основном, что происходит, когда Вы смешиваете Состав или Агрегирование с Доступными классами. Как упомянуто, первый выход должен был бы осуществить рефакторинг waitHandle из шнурка.

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

Но можно опустить деструктор и GC.SuppressFinalize (это); и возможно очистка виртуальная пустота Располагает (bool располагающий) немного.

3
ответ дан 23 November 2019 в 23:41
поделиться

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

3
ответ дан 23 November 2019 в 23:41
поделиться

Интересно, если Driver определяется как выше:

class Driver
{
    Shoe[] shoes = { new Shoe(), new Shoe() };
}

Затем, когда Shoe сделан IDisposable, FxCop (v1.36) не жалуется это Driver должен также быть IDisposable.

Однако, если это определяется как это:

class Driver
{
    Shoe leftShoe = new Shoe();
    Shoe rightShoe = new Shoe();
}

затем это будет жаловаться.

Я подозреваю, что это - просто ограничение FxCop, а не решение, потому что в первой версии Shoe экземпляры все еще создаются Driver и все еще потребность, которая будет расположена так или иначе.

3
ответ дан 23 November 2019 в 23:41
поделиться

Я не думаю, что есть технический способ предотвратить распространение IDisposable, если вы держите вашу конструкцию так плотно связаны. Тогда стоит задуматься, правильна ли конструкция.

В вашем примере, я думаю, имеет смысл иметь шнурок для обуви, и, возможно, водитель должен иметь свою обувь. Однако автобус не должен владеть водителем. Обычно водители автобусов не следуют за автобусами до свалки :). В случае с водителями и обувью, водители редко делают свою собственную обувь, то есть на самом деле они не "владеют" своей обувью.

Альтернативная конструкция может быть:

class Bus
{
   IDriver busDriver = null;
   public void SetDriver(IDriver d) { busDriver = d; }
}

class Driver : IDriver
{
   IShoePair shoes = null;
   public void PutShoesOn(IShoePair p) { shoes = p; }
}

class ShoePairWithDisposableLaces : IShoePair, IDisposable
{
   Shoelace lace = new Shoelace();
}

class Shoelace : IDisposable
{
   ...
}

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

3
ответ дан 23 November 2019 в 23:41
поделиться

Чтобы предотвратить распространение IDisposable, вы должны попытаться инкапсулировать использование одноразового объекта внутри одного метода. Попробуйте спроектировать Shoelace по-другому:

class Shoelace { 
  bool tied = false; 

  public void Tie() {

    using (var waitHandle = new AutoResetEvent(false)) {

      // you can even pass the disposable to other methods
      OtherMethod(waitHandle);

      // or hold it in a field (but FxCop will complain that your class is not disposable),
      // as long as you take control of its lifecycle
      _waitHandle = waitHandle;
      OtherMethodThatUsesTheWaitHandleFromTheField();

    } 

  }
} 

Область применения ручки ожидания ограничена методом Tie, и классу не нужно иметь одноразовое поле, а значит, не нужно быть одноразовым самому.

Поскольку ручка ожидания является деталью реализации внутри Shoelace, она не должна каким-либо образом изменять его публичный интерфейс, например, добавлять новый интерфейс в его объявление. Что произойдет, когда вам больше не понадобится одноразовое поле, удалите ли вы объявление IDisposable? Если вы подумаете об Shoelace абстракции, то быстро поймете, что она не должна быть загрязнена инфраструктурными зависимостями, такими как IDisposable. IDisposable следует зарезервировать для классов, чья абстракция инкапсулирует ресурс, требующий детерминированной очистки; т.е. для классов, где одноразовость является частью абстракции.

14
ответ дан 23 November 2019 в 23:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: