Такая конструкция требует отписки для исключения утечек памяти ?
От: Аноним  
Дата: 11.05.13 18:36
Оценка:
button.MouseClick+=(sender,args)=>{ var some_object = new object(); /*do_something*/ }


и будет ли утечка в этом случае


object some_object;

void Initialize()
{
  some_object = new object();
  button.MouseClick+=(sender,args)=>{ /*do_something with some_object*/ }
}
Re: Такая конструкция требует отписки для исключения утечек памяти ?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 11.05.13 18:38
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>
А>button.MouseClick+=(sender,args)=>{ var some_object = new object(); /*do_something*/ }
А>


А>и будет ли утечка в этом случае


Не очень понятно что ты считаешь утечкой. Если экземпляр object, то он будет каждый раз создаваться при вызове события и убираться GC при первой же сборке. Если экземпляр делегата, то он так и будет висеть в списке подписчиков до смерти button.
... << RSDN@Home 1.2.0 alpha 5 rev. 99 on Windows 8 6.2.9200.0>>
AVK Blog
Re: Такая конструкция требует отписки для исключения утечек памяти ?
От: TK Лес кывт.рф
Дата: 11.05.13 22:27
Оценка:
Здравствуйте, Аноним, Вы писали:

А>
А>button.MouseClick+=(sender,args)=>{ var some_object = new object(); /*do_something*/ }
А>

А>и будет ли утечка в этом случае
А>

Без отписки подписчик на MouseClick будет жить пока существует экземпляр button. В большинстве случаев подобный код отписки не требует. 

А>object some_object;
А>void Initialize()
А>{
А>  some_object = new object();
А>  button.MouseClick+=(sender,args)=>{ /*do_something with some_object*/ }
А>}
А>


в первом случае some_object будет создаваться каждый раз, а во втором случае только в момент вызова Initialize
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[2]: Такая конструкция требует отписки для исключения утечек памяти ?
От: Sshur Россия http://shurygin-sergey.livejournal.com
Дата: 12.05.13 08:02
Оценка:
Здравствуйте, TK, Вы писали:


TK>Без отписки подписчик на MouseClick будет жить пока существует экземпляр button. В большинстве случаев подобный код отписки не требует.


Надо только понимать, что если подписываешься на событие объекта, время жизни которого больше, чем код обработчика события, то код обработчика будет жить все время жизни объекта. Если это лямбда (которая, если не ошибаюсь, развернется в анонимный класс) — то это не так страшно, а если метод какой-то большой формы — тот тут уже могут быть проблемы. Например, когда экземпляр дочерней mdi формы подписывается на событие главной и не отписывается.. А все что живет внутри одной формы, это безопасно

Если использовать сторонние компоненты, то подписка может быть неявная. Я очень часто вижу код, когда какой-то компонент подписывается в конструкторе на какое-нибудь событие глобального статического класса и при этом отписывается в диспозе. При таком подходе получаются очень качественно замаскированные грабли, так как диспоз многие забывают
Шурыгин Сергей

"Не следует преумножать сущности сверх необходимости" (с) Оккам
Re[2]: Такая конструкция требует отписки для исключения утечек памяти ?
От: pr0ff  
Дата: 13.05.13 11:36
Оценка:
Здравствуйте, TK, Вы писали:
TK>Без отписки подписчик на MouseClick будет жить пока существует экземпляр button. В большинстве случаев подобный код отписки не требует.
Конкретно в этих случаях подписчик не будет привязан к экземпляру button. Подписчик будет жить если анонимный делегат будет использовать любые экземплярные члены, так же будут жить экземляры классов, хранящихся в переменных, используемых делегатом. Так же если на событие подписать статический метод, то это тоже не приведет к продлению жизни экземпляра. Ну а про разницу времени жизни уже сказали.
Re[3]: Такая конструкция требует отписки для исключения утечек памяти ?
От: TK Лес кывт.рф
Дата: 13.05.13 12:21
Оценка: +1
Здравствуйте, pr0ff, Вы писали:

TK>>Без отписки подписчик на MouseClick будет жить пока существует экземпляр button. В большинстве случаев подобный код отписки не требует.

P>Конкретно в этих случаях подписчик не будет привязан к экземпляру button.

Подписчик всегда привязан к тому событию на которое он подписан (или его подписали).
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[4]: Такая конструкция требует отписки для исключения утечек памяти ?
От: pr0ff  
Дата: 13.05.13 12:51
Оценка:
Здравствуйте, TK, Вы писали:

TK>Здравствуйте, pr0ff, Вы писали:


TK>>>Без отписки подписчик на MouseClick будет жить пока существует экземпляр button. В большинстве случаев подобный код отписки не требует.

P>>Конкретно в этих случаях подписчик не будет привязан к экземпляру button.

TK>Подписчик всегда привязан к тому событию на которое он подписан (или его подписали).

Это да, но, на самом деле, в перечисленных мною случаях подписчик отсутствует. Делегат ссылается на метод и на экземпляр объекта (подписчик). Если этот метод статический, то экземпляр отсутствует. В случае с анонимным делегатом без замыкания, метод будет статическим. В случае с анонимным делегатом с замыканием, метод будет в анонимном классе, экземпляр которого будет содержать в себе все используемые переменные.
Re[4]: Такая конструкция требует отписки для исключения утечек памяти ?
От: pr0ff  
Дата: 13.05.13 13:00
Оценка:
Здравствуйте, TK, Вы писали:
TK>Подписчик всегда привязан к тому событию на которое он подписан (или его подписали).
Беру свои слова назад частично. Я был уверен, что во втором случае object является переменной метода, а не полем класса. Во втором примере экземпляр текущего класса (подписчика) будет жить пока живет экземпляр button
Re[5]: Такая конструкция требует отписки для исключения утечек памяти ?
От: TK Лес кывт.рф
Дата: 13.05.13 13:04
Оценка:
Здравствуйте, pr0ff, Вы писали:

TK>>Подписчик всегда привязан к тому событию на которое он подписан (или его подписали).

P>Это да, но, на самом деле, в перечисленных мною случаях подписчик отсутствует.

т.е. подписка есть, а подписчика нет?
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[6]: Такая конструкция требует отписки для исключения утечек памяти ?
От: pr0ff  
Дата: 13.05.13 13:41
Оценка: :)
Здравствуйте, TK, Вы писали:
TK>т.е. подписка есть, а подписчика нет?
ну если Вам так будет удобней, то можете подписчиком считать тип (хотя в делегате нет прямой ссылки на него)
Запускать в релизной конфигурации:
    internal class Class1
    {
        private Delegate _handler;
        public event EventHandler Event
        {
            add
            {
                _handler = Delegate.Combine(_handler, value);
                Console.WriteLine("class: {0}, method: {1}, target: {2}", value.Method.DeclaringType, value.Method,
                    value.Target ?? "null");
            }
            remove { _handler = Delegate.Remove(_handler, value); }
        }
        ~Class1()
        {
            Console.WriteLine("Class1 finalized");
        }
    }
    internal class Class2
    {
        public void Method(Class1 c1)
        {
            var o = new object();
            c1.Event += (sender, eventArgs) => { };
            c1.Event += (sender, eventArgs) => Console.WriteLine(o);
            c1.Event += Handler;
        }
        private static void Handler(object sender, EventArgs eventArgs)
        {
        }
        ~Class2()
        {
            Console.WriteLine("Class2 finalized");
        }
    }
    internal class Class3
    {
        private readonly object o = new object();
        public void Method(Class1 c1)
        {
            c1.Event += (sender, eventArgs) => Console.WriteLine(o);
        }
        ~Class3()
        {
            Console.WriteLine("Class3 finalized");
        }
    }
    internal class Class4
    {
        public void Method(Class1 c1)
        {
            c1.Event += Handler;
        }
        private void Handler(object sender, EventArgs eventArgs)
        {
        }
        ~Class4()
        {
            Console.WriteLine("Class3 finalized");
        }
    }
    internal class Program
    {
        private static Class1 c1;
        private static void Main(string[] args)
        {
            c1 = new Class1();
            var c2 = new Class2();
            c2.Method(c1);
            var c3 = new Class3();
            c3.Method(c1);
            var c4 = new Class4();
            c4.Method(c1);

            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
            Console.ReadLine();
        }
    }

Результат:
class: ConsoleApplication10.Class2, method: Void <Method>b__0(System.Object, System.EventArgs), target: null
class: ConsoleApplication10.Class2+<>c__DisplayClass3, method: Void <Method>b__1(System.Object, System.EventArgs), target: ConsoleApplication10.Class2+<>c__DisplayClass3
class: ConsoleApplication10.Class2, method: Void Handler(System.Object, System.EventArgs), target: null
class: ConsoleApplication10.Class3, method: Void <Method>b__0(System.Object, System.EventArgs), target: ConsoleApplication10.Class3
class: ConsoleApplication10.Class4, method: Void Handler(System.Object, System.EventArgs), target: ConsoleApplication10.Class4
Class2 finalized


Как видите, Class2 не пережил сборку мусора, а внутри него в 1 и 3 способах подписчика нет, а во 2 подписчик — экземпляр анонимного типа
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.