Так что я в основном подвергаю сомнению все, что узнал о сборке мусора в C #.
У меня есть класс с именем User
, User
имеет 2 свойства: (system.Timers)Timer
и свойство name каждый раз, когда создается User
. Я связываю событие, событие состоит из каждых 0,5 секунд. произошло.
Проблема в том, что каждый раз, когда я связываю событие с User
, создается впечатление, что сборщик мусора просто не избавляется от класса, даже если я удаляю его из списка.
User
класс
public class User
{
/// <summary>
/// A specific name that I give to created users so I know which one was created/destroyed
/// </summary>
public string Name { get; set; }
/// <summary>
/// A timer that fires an event every so often
/// </summary>
public Timer _timer;
public User(string name)
{
Name = name;
// Initializing the Timer
// Here is where it get interesting when I initialize the Timer class this user class just doesn't get disposed
// even if I set "Enabled" to false
_timer = new Timer()
{
AutoReset = true,
Enabled = true,
Interval = TimeSpan.FromSeconds(0.5).TotalMilliseconds,
};
// Notifying console that user has been created
IoC.Log().WriteLine($"\n{Name} was created\n");
// Bind the event
// I've attempted to bind the event as lambada function and as a
// "normal" function both seem to be causing the "error"
//_timer.Elapsed += (sender, e) => IoC.Log().WriteLine($"{Name} elapsed");
}
/*
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
// Notify that an event has been called
IoC.Log().WriteLine($"{Name} elapsed");
}*/
~User()
{
// Notify that user has been destroyed/disposed
IoC.Log().WriteLine($"\n{Name} destroyed <---------- \n");
}
}
UserList
Класс
public class UserList
{
private ObservableCollection<User> _user = new ObservableCollection<User>();
/// <summary>
/// Stores a list of users
/// </summary>
public ObservableCollection<User> Users
{
get => _user;
set => _user = value;
}
public UserList()
{
Users.CollectionChanged += Users_CollectionChanged;
}
private void Users_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// When a user is added to the list
if (e.Action == NotifyCollectionChangedAction.Add)
{
// Get the new user
User addedUser = Users[e.NewStartingIndex];
// Bind an Elapsed event to the user's timer
addedUser._timer.Elapsed += (_sender, _e) => IoC.Log().WriteLine($"{addedUser.Name} elapsed");
};
}
}
Класс звонков
защищенное переопределение async void OnStartup (StartupEventArgs e)
{
// Настройка DI (использование ninject с постоянной привязкой к классу UserList в качестве теста)
IoC.Setup ();
// Initialize a window
MainWindow = new MainWindow();
MainWindow.Show();
// Create a scoped user
// Should be destoryed as soon as we get out of scope
// Does actaully get disposed (because I am not binding an event ?)
{
User user = new User("user");
};
// Adding user as a new instance
IoC.Get<UserList>().Users.Add(new User("New User1"));
IoC.Get<UserList>().Users.Add(new User("New user2"));
// Creating user as a reference
User user1 = new User("user1");
User user2 = new User("user2");
// Adding the "reference" userlist
IoC.Get<UserList>().Users.Add(user1);
IoC.Get<UserList>().Users.Add(user2);
// Notify that we are deleting users
IoC.Log().WriteLine("\nWaiting 5 seconds\n");
await Task.Delay(3000);
IoC.Log().WriteLine("\nDeleting users..\n");
// Removing created users
IoC.Get<UserList>().Users.RemoveAt(3);
IoC.Get<UserList>().Users.RemoveAt(2);
IoC.Get<UserList>().Users.RemoveAt(1);
IoC.Get<UserList>().Users.RemoveAt(0);
// NOtify that we finished
IoC.Log().WriteLine("\nFinised deleting\n");
// And after a while the Garbage collector should dispose of the references
return;
Вот что я пытался сделать до сих пор:
Создание события внутри вызывающего класса, которое будет таким же, как ElapsedEvent
, и связывание события при создании объекта User
и когда я собираюсь избавиться от объекта User
, я отменяю событие
Класс вызова
// Not binding any event to the user's that will be added to the list
// This works fine they are disposed like intended
//But this scoped user appears to not be disposed
User user;
{
user = new User("user");
user._timer.Elapsed += _timer_Elapsed;
};
// Logic that takes a while
// So we can see the event in action
await Task.Delay(3000)
// Unbind event.
// But 'user' is still not being disposed even after existing scope
user._timer.Elapsed -= _timer_Elapsed;
Попытка связать событие внутри класса UserList. Это не сработало, потому что когда я вызывал «CollectionChanged», у меня не было доступа к удаленному пользователю, и не было никакого способа отменить привязку события
UserList
класс
private void Users_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// When a user is added to the list
if (e.Action == NotifyCollectionChangedAction.Add)
{
// Get the new user
User addedUser = Users[e.NewStartingIndex];
/ Bind an Elapsed event to the user's timer
// This works because I have access to the newly created/added user
//addedUser._timer.Elapsed += (_sender, _e) => IoC.Log().WriteLine($"{addedUser.Name} elapsed");
};
}
// If a user is removed from the list
else
{
// After all user's have been removed this throws an OutOfRangeException, Furthermore I never have acces to the CURRENT user that was removed
User addedUser = Users[e.OldStartingIndex];
};