订阅事件可防止列表中的对象被垃圾回收

时间:2018-10-31 16:18:34

标签: c# .net events garbage-collection

所以我基本上是在质疑到目前为止我所学到的有关C#垃圾收集的一切。

我有一个名为User的类,User具有2个属性(system.Timers)Timer和名称属性,每次创建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"); 
            };
        }
    }

呼叫班

受保护的覆盖异步无效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];
      };

0 个答案:

没有答案