Слабые ссылки остаются в живых

У меня есть интерфейс: IRemoteDataChangedListener

public interface IRemoteDataChangedListener<TData>
{
    void DataReceived(TData newData);
}

И класс, RealtimeEventService

public class RealtimeEventService : IRealtimeEventService
{
    private readonly IEventListener listener;

    private readonly List<Tuple<Type, WeakReference>> dataCreated;

    public RealtimeEventService(IEventListener eventListener)
    {
        this.dataCreated = new List<Tuple<Type, WeakReference>>();
        this.listener = eventListener;
        this.listener.EventReceived += this.ListenerOnEventReceived;
    }

    private void ListenerOnEventReceived(EventMessage message)
    {
        Type type = message.GetType();

        if (type == typeof(NotificationReadEventMessage))
        {
            this.DataChanged((NotificationReadEventMessage)message);
        }
    }

    public void SubscribeDataChanged<TEventMessage>(IRemoteDataChangedListener<TEventMessage> dataChangedListener) where TEventMessage : EventMessage, new()
    {
        this.dataCreated.Add(Tuple.Create(typeof(TEventMessage), new WeakReference(dataChangedListener)));
    }

    internal void DataChanged<TKey>(TKey newData)
        where TKey : class, new()
    {
        LoopAndFilter<TKey>(this.dataCreated, listener => listener.DataReceived(newData));
    }

    private static void LoopAndFilter<TKey>(ICollection<Tuple<Type, WeakReference>> collection,
        Action<IRemoteDataChangedListener<TKey>> success) where TKey : class
    {
        foreach (var reference in collection.ToArray())
        {
            if (!reference.Item2.IsAlive)
            {
                collection.Remove(reference);
                continue;
            }

            if (reference.Item1 != typeof(TKey))
                continue;

            success((IRemoteDataChangedListener<TKey>)reference.Item2.Target);
        }
    }

    #endregion
}

Всякий раз, когда я создаю тестовый класс, который наследует IRemoteDataChangedListener с NotificationReadEventMessage в качестве универсального аргумента, и использую экземпляр этого класса с SubscribeDataChanged(), он просто подключается, и метод вызывается.

Проблема в том, что, когда я устанавливаю ссылку на экземпляр в значение null и запускаю GC.Collect(), он должен быть равен нулю, и в следующий раз, когда будет запущен метод LoopAndFilter RealtimeEventService, он должен обнаружить, что он больше не существует, и удалить Weakreference из список.

Однако это не так. Когда я проверяю значение (In LoopAndFilter), после установки ссылки экземпляра на ноль в тесте, значение все равно отображается как Alive, являясь истинным.

И теперь я часами смотрю на этот код, и я просто не могу нигде найти, чтобы иметь сильную ссылку на класс...

Любая помощь?

@Edit: модульный тест (с использованием библиотек Moq и Should):

public class RealtimeEventServiceTests
{
    [Fact]
    public void VerifyWeakReferencesWorksAsIntended()
    {
        var eventListenerMock = new Mock<IEventListener>();
        IRealtimeEventService service = new RealtimeEventService(eventListenerMock.Object);

        bool called = false;
        RemoteDataTest dataChangedListener = new RemoteDataTest();
        dataChangedListener.Called += (sender, args) => called = true;
        service.SubscribeDataChanged(dataChangedListener);

        called.ShouldBeFalse();
        ((RealtimeEventService)service).DataChanged(new NotificationReadEventMessage());
        called.ShouldBeTrue();

        called = false;
        dataChangedListener = null;
        GC.Collect();

        called.ShouldBeFalse();
        ((RealtimeEventService)service).DataChanged(new NotificationReadEventMessage());
        called.ShouldBeFalse();
    }
}

public class RemoteDataTest : IRemoteDataChangedListener<NotificationReadEventMessage>
{
    public event EventHandler Called;

    public void DataReceived(NotificationReadEventMessage newData)
    {
        if (Called != null) Called(this, null);
    }
}

1 ответ

Решение

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

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

Я воспользовался советом Эвана и Скотта Чемберлена, так что спасибо за это!

Другие вопросы по тегам