弱引用仍然存在
Weak References stays alive
我有一个接口:IRemoteDataChangedListener
public interface IRemoteDataChangedListener<TData>
{
void DataReceived(TData newData);
}
还有一个class,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
}
每当我创建一个测试 class 继承 IRemoteDataChangedListener 并将 NotificationReadEventMessage 作为通用参数,并使用此 class 的一个实例与 SubscribeDataChanged() 时,它就会很好地连接起来,并且方法被调用。
问题是,当我将实例引用设置为 null 和 运行 GC.Collect() 时,它应该为 null,而下一次 RealtimeEventService 的 LoopAndFilter 方法 运行s,它应该检测到它不再存在,并从列表中删除 Weakreference。
然而事实并非如此。当我检查值(在 LoopAndFilter 中)时,在测试中将实例引用设置为 null 后,该值仍然显示为 Alive 为真。
现在我已经盯着这段代码看了好几个小时了,我根本找不到任何地方可以强烈引用 class...
有什么帮助吗?
@编辑:单元测试(使用 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);
}
}
事实证明,当我回到家并在家编译它时,它 运行 就好了。当我回去工作时,它在那里也工作得很好。
我猜它只是那些在无法解释的时间神奇地消失的幽灵般的错误之一。我很高兴摆脱它。
我确实听取了 Ewan & Scott Chamberlain 的建议,非常感谢!
我有一个接口:IRemoteDataChangedListener
public interface IRemoteDataChangedListener<TData>
{
void DataReceived(TData newData);
}
还有一个class,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
}
每当我创建一个测试 class 继承 IRemoteDataChangedListener 并将 NotificationReadEventMessage 作为通用参数,并使用此 class 的一个实例与 SubscribeDataChanged() 时,它就会很好地连接起来,并且方法被调用。
问题是,当我将实例引用设置为 null 和 运行 GC.Collect() 时,它应该为 null,而下一次 RealtimeEventService 的 LoopAndFilter 方法 运行s,它应该检测到它不再存在,并从列表中删除 Weakreference。
然而事实并非如此。当我检查值(在 LoopAndFilter 中)时,在测试中将实例引用设置为 null 后,该值仍然显示为 Alive 为真。
现在我已经盯着这段代码看了好几个小时了,我根本找不到任何地方可以强烈引用 class...
有什么帮助吗?
@编辑:单元测试(使用 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);
}
}
事实证明,当我回到家并在家编译它时,它 运行 就好了。当我回去工作时,它在那里也工作得很好。
我猜它只是那些在无法解释的时间神奇地消失的幽灵般的错误之一。我很高兴摆脱它。
我确实听取了 Ewan & Scott Chamberlain 的建议,非常感谢!