У меня есть класс, который хранит статический список экземпляров соединения. При обратных вызовах вызывается каждый экземпляр в списке, и если вызов не удался, экземпляр удаляется из списка.
Дьявол подробно, поскольку синхронизация необходима при добавлении, удалении и перечислении элементов списка. В настоящее время я использую этот шаблон:
class Foo : IDisposable
{
private static readonly List<Foo> _Connections = new List<Foo> ();
private readonly IFooCallback CallbackChannel;
internal Foo ()
{
CallbackChannel = OperationContext.Current.GetCallbackChannel<IFooCallback> ();
lock (_Connections) {
_Connections.Add (this);
OperationContext.Current.Channel.Closing += (s, e) => Dispose ();
OperationContext.Current.Channel.Faulted += (s, e) => Dispose ();
}
}
public void Dispose ()
{
lock (_Connections) {
_Connections.Remove (this);
}
}
private void RaiseCallback ()
{
List<Foo> connections;
lock (_Connections) {
connections = new List<Foo> (_Connections);
}
foreach (var con in connections) {
try {
con.CallbackChannel.SomeCallback ();
}
catch (CommunicationException) {
OperationContext.Current.Channel.Abort ();
}
catch (TimeoutException) {
OperationContext.Current.Channel.Abort ();
}
}
}
}
Моя идея:
- Статический список экземпляров, каждый экземпляр хранит канал CB.
- Экземпляр удаляется, когда канал закрыт или прерван.
- При обратном вызове создается копия списка (синхронно) и нумеруется (не синхронизируется).
- При сбое обратного вызова канал прерывается.
Сбой обратного вызова вызывает прерывание канала, что, в свою очередь, вызывает удаление и удаление из списка. Это может произойти или не произойти в одном и том же потоке (это не может быть гарантировано, поскольку Dispose может быть вызван в любое время из-за другого события).
У меня вопрос: является ли это общим шаблоном для хранения экземпляров и обработки ошибок обратного вызова, или как его можно улучшить? Копирование списка перед перечислением в RaiseCallback - это ошибка, или это правильно?