弱引用与弱委托

一、弱引用:

我们设计全局缓存时,使用静态或全局字段来引用某个对象,做到一次创建多次使用。比如:

    class Program
    {
        private static DataCache _cache;

        public static DataCache Cache
        {
            get
            {
                if(_cache == null)
                    _cache = new DataCache();
                return _cache;
            }
        }

        static void Main(string[] args)
        {
            byte [] ss = new byte[]{1,2,3};
            GC.Collect();
            Console.WriteLine("GC执行完毕");
            Console.Read();
        }

    }
   class DataCache
   {
       private IList<string> datas;
   }

但这样存在弊端:

  • DataCache没频繁使用时,浪费内存空间。
  • 由于GC只能回收不可达对象,所以没有办法回收这些资源。

WeakReference出场:即在引用对象的同时仍然允许对该对象进行垃圾回收。

所以我们可以这样设计缓存:

class Program
    {
        static  WeakReference _cache = new WeakReference(null);

        public static DataCache Cache
        {
            get
            {
                DataCache cache = _cache.Target as DataCache;
                if(cache == null)
                {
                    cache = new DataCache();
                    _cache.Target = cache;
                }
                return cache;
            }
        }

        static void Main(string[] args)
        {
            byte [] ss = new byte[]{1,2,3};
            Cache.Test();
            Cache.Test();
            GC.Collect();
            Console.WriteLine("GC执行完毕");
            Cache.Test();
            Console.Read();
        }

    }
   class DataCache
   {
       private IList<string> datas;

       ~DataCache()
       {
           Console.WriteLine("Destory..."); 
       }

       public void Test()
       {
           Console.WriteLine("Test");
       }
   }

二、弱委托

弱委托解决当委托对象的生命周期足够的长时,导致委托内部持有的强对象不能回收,

比如:

    class Program
    {
        static void Main(string[] args)
        {
            Action<string> sAction = new Action<string>(new ClassTest().Print);
            sAction("abc");
            GC.Collect();
            sAction("abc");
        }

    }

    internal class ClassTest
    {
        public void Print(string s)
        {
            Console.WriteLine(s);
        }
    }

输出结果为:abc abc
为了解决当垃圾回收进行时,委托的对象任然存在,就用到了WeakReference

  class Program
    {
        static void Main(string[] args)
        {
            Action<string> sAction = new Action<string>(new ClassTest().Print);

            WeakReference weakReference = new WeakReference(new ClassTest());
            sAction = (s) =>
                          {
                              object o = weakReference.Target;
                              if (o != null)
                              {
                                  ((ClassTest)o).Print(s);
                              }
                          };
            sAction("def");
            GC.Collect();
            sAction("def");
        }

    }

    internal class ClassTest
    {
        public void Print(string s)
        {
            Console.WriteLine(s);
        }
    }

输出结果当然只有一个def了。

CLR var C#中的弱委托:

 public abstract class WeakDelegate<TDelegate> where TDelegate : class /* MulticastDelegate */ {
        // This lightweight private struct puts a compile-time type-safety wrapper around the non-generic WeakReference class
        private struct WeakReference<T> : IDisposable where T : class {
            private WeakReference m_weakReference;

            public WeakReference(T target) { m_weakReference = new WeakReference(target); }
            public T Target { get { return (T)m_weakReference.Target; } }
            public void Dispose() { m_weakReference = null; }
        }

        private WeakReference<TDelegate> m_weakDelegate;
        private Action<TDelegate> m_removeDelegateCode;

        public WeakDelegate(TDelegate @delegate) {
            var md = (MulticastDelegate)(Object)@delegate;
            if (md.Target == null)
                throw new ArgumentException("There is no reason to make a WeakDelegate to a static method.");

            // Save a WeakReference to the delegate
            m_weakDelegate = new WeakReference<TDelegate>(@delegate);
        }

        public Action<TDelegate> RemoveDelegateCode {
            set {
                // Save the delegate that refers to code that knows how to remove the 
                // WeakDelegate object when the non-weak delegate object is GC’d
                m_removeDelegateCode = value;
            }
        }

        protected TDelegate GetRealDelegate() {
            // If the real delegate hasn't been GC'd yet, just return it
            TDelegate realDelegate = m_weakDelegate.Target;
            if (realDelegate != null) return realDelegate;

            // The real delegate was GC'd, we don't need our WeakReference to it anymore (it can be GC'd)
            m_weakDelegate.Dispose();

            // Remove the delegate from the chain (if the user told us how)
            if (m_removeDelegateCode != null) {
                m_removeDelegateCode(GetDelegate());
                m_removeDelegateCode = null;  // Let the remove handler delegate be GC'd
            }
            return null;   // The real delegate was GC'd and can't be called
        }

        // All derived classes must return a delegate to a private method matching the TDelegate type
        public abstract TDelegate GetDelegate();

        // Implicit conversion operator to convert a WeakDelegate object to an actual delegate
        public static implicit operator TDelegate(WeakDelegate<TDelegate> @delegate) {
            return @delegate.GetDelegate();
        }
    }

    // This class provides support for the non-generic EventHandler delegate
    public sealed class WeakEventHandler : WeakDelegate<EventHandler> {
        public WeakEventHandler(EventHandler @delegate) : base(@delegate) { }

        /// <summary>Returns a reference to the non-generic EventHandler delegate</summary>
        public override EventHandler GetDelegate() { return Callback; }

        // This private method must match the desired delegate’s signature
        private void Callback(Object sender, EventArgs e) {
            // If the target hasn't been GC'd invoke it
            var eh = base.GetRealDelegate();
            if (eh != null) eh(sender, e);
        }
    }

    // This WeakDelegate partial class provides support for the generic EventHandler<TEventArgs> delegate
    public sealed class WeakEventHandler<TEventArgs> : WeakDelegate<EventHandler<TEventArgs>> where TEventArgs : EventArgs {
        public WeakEventHandler(EventHandler<TEventArgs> @delegate) : base(@delegate) { }

        /// <summary>Returns a reference to the generic EventHandler<typeparam name="TEventArgs"/> delegate</summary>
        public override EventHandler<TEventArgs> GetDelegate() { return Callback; }

        private void Callback(Object sender, TEventArgs e) {
            // If the target hasn't been GC'd invoke it
            var eh = base.GetRealDelegate();
            if (eh != null) eh(sender, e);
        }
    }



### WeakReference弱引用 WeakReference 是一种特殊的引用类型,其作用在于避免对对象的强引用,从而使对象在没有其他强引用时可以被垃圾回收器回收。在事件模式中,使用 WeakReference 能够避免订阅者被强引用,进而防止因事件订阅导致对象无法被回收的问题。 ### WeakEventManager事件 WeakEventManager 是用于实现事件模式的机制。在 .NET 中,特别是在 WPF 框架里有相关的类来实现此机制。WPF 框架自带的 WeakEventManager 功能有限,继承实现难度高,但性能高,WPF 绑定等机制的底层实现会用到该类型;而 WPF 框架自带的泛型类 WeakEventManager<TEventSource, TEventArgs> 能让开发者更容易实现自己的事件,不过性能较差 [^2]。 WeakEventManager 在实现时会使用 ConditionalWeakTable,它能将处理程序(委托)的生命周期目标对象的生命周期相关联。以 Windows Presentation Foundation 中的 WeakEventManager 类为例,就借助 ConditionalWeakTable 把事件处理程序和事件源对象关联起来,当事件源对象被垃圾回收时,对应的事件处理程序也不会阻碍其回收 [^3]。 以下是一个简单的 C# 代码示例,展示如何使用弱引用事件管理: ```csharp using System; using System.Windows; using System.Windows.Threading; // 事件参数类 public class CustomEventArgs : EventArgs { public string Message { get; set; } } // 事件发布者类 public class EventPublisher { public event EventHandler<CustomEventArgs> CustomEvent; public void RaiseEvent() { CustomEvent?.Invoke(this, new CustomEventArgs { Message = "Event raised!" }); } } // 事件订阅者类 public class EventSubscriber { public void HandleEvent(object sender, CustomEventArgs e) { Console.WriteLine($"Received message: {e.Message}"); } } class Program { static void Main() { EventPublisher publisher = new EventPublisher(); EventSubscriber subscriber = new EventSubscriber(); // 使用 WeakEventManager 订阅事件 WeakEventManager<EventPublisher, CustomEventArgs>.AddHandler(publisher, "CustomEvent", subscriber.HandleEvent); publisher.RaiseEvent(); // 模拟垃圾回收 subscriber = null; GC.Collect(); GC.WaitForPendingFinalizers(); publisher.RaiseEvent(); } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值