Можно ли перехватить объекты, собираемые GC? - PullRequest
5 голосов
/ 28 декабря 2011

Предположим, у меня есть WeakReference целевой сильной ссылки. Я хотел бы получить информацию, когда сам целевой объект собирается GC. Возможно ли это?

РЕДАКТИРОВАТЬ: Добавление кода в финализатор / деструктор здесь не вариант. Мне нужно что-то, что не зависит от кода класса.

Ответы [ 3 ]

6 голосов
/ 14 марта 2012

Это возможно в .NET 4.0 и после использования ConditionalWeakTable<TKey, TValue>. Спасибо этому и другим сайтам. Это следует из доказательства концепции кода:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;

namespace Test
{
    public static class GCInterceptor
    {
        private static ConditionalWeakTable<object, CallbackRef> _table;

        static GCInterceptor()
        {
            _table = new ConditionalWeakTable<object, CallbackRef>();
        }

        public static void RegisterGCEvent(this object obj, Action<int> action)
        {
            CallbackRef callbackRef;
            bool found = _table.TryGetValue(obj, out callbackRef);
            if (found)
            {
                callbackRef.Collected += action;
                return;
            }

            int hashCode = RuntimeHelpers.GetHashCode(obj);
            callbackRef = new CallbackRef(hashCode);
            callbackRef.Collected += action;
            _table.Add(obj, callbackRef);
        }

        public static void DeregisterGCEvent(this object obj, Action<int> action)
        {
            CallbackRef callbackRef;
            bool found = _table.TryGetValue(obj, out callbackRef);
            if (!found)
                throw new Exception("No events registered");

            callbackRef.Collected -= action;
        }

        private class CallbackRef
        {
            private int _hashCode;
            public event Action<int> Collected;

            public CallbackRef(int hashCode)
            {
                _hashCode = hashCode;
            }

            ~CallbackRef()
            {
                Action<int> handle = Collected;
                if (handle != null)
                    handle(_hashCode);
            }
        }
    }
}

Протестировано со следующим кодом:

public partial class Form1 : Form
{
    private object _obj;

    public Form1()
    {
        InitializeComponent();

        _obj = new object();

        _obj.RegisterGCEvent(delegate(int hashCode)
        {
            MessageBox.Show("Object with hash code " + hashCode + " recently collected");
        });
    }

    private void button1_Click(object sender, EventArgs e)
    {
        _obj = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}
2 голосов
/ 28 декабря 2011

Как насчет Object.Finalize() метода? Разве это не будет вызвано после завершения?

0 голосов
/ 28 декабря 2011

Вы можете использовать перехват для захвата Finalize для каждого класса, который унаследован от пользовательского интерфейса / класса.Я думаю, это то, чего вы хотите добиться, верно?Вы можете использовать Unity для этого. Здесь - очень короткий пример того, как перехватить Unity.

...