C#中的弱引用

本文介绍.NET中的弱引用(WeakReference),解释如何利用弱引用平衡内存使用与对象保留,包括短弱引用与长弱引用的区别及应用场景。

Weak References


The garbage collector cannot collect an object in use by an application while the application's code can reach that object. The application is said to have a strong reference to the object.

A weak reference permits the garbage collector to collect the object while still allowing the application to access the object. A weak reference is valid only during the indeterminate amount of time until the object is collected when no strong references exist. When you use a weak reference, the application can still obtain a strong reference to the object, which prevents it from being collected. However, there is always the risk that the garbage collector will get to the object first before a strong reference is reestablished.

Weak references are useful for objects that use a lot of memory, but can be recreated easily if they are reclaimed by garbage collection.

Suppose a tree view in a Windows Forms application displays a complex hierarchical choice of options to the user. If the underlying data is large, keeping the tree in memory is inefficient when the user is involved with something else in the application.

When the user switches away to another part of the application, you can use the WeakReference class to create a weak reference to the tree and destroy all strong references. When the user switches back to the tree, the application attempts to obtain a strong reference to the tree and, if successful, avoids reconstructing the tree.

To establish a weak reference with an object, you create a WeakReference using the instance of the object to be tracked. You then set the Target property to that object and set the object tonull. For a code example, see WeakReference in the class library.

You can create a short weak reference or a long weak reference:

  • Short

    The target of a short weak reference becomes null when the object is reclaimed by garbage collection. The weak reference is itself a managed object, and is subject to garbage collection just like any other managed object. A short weak reference is the default constructor for WeakReference.

  • Long

    A long weak reference is retained after the object's Finalize method has been called. This allows the object to be recreated, but the state of the object remains unpredictable. To use a long reference, specify true in the WeakReference constructor.

    If the object's type does not have a Finalize method, the short weak reference functionality applies and the weak reference is valid only until the target is collected, which can occur anytime after the finalizer is run.

To establish a strong reference and use the object again, cast the Target property of a WeakReference to the type of the object. If the Target property returns null, the object was collected; otherwise, you can continue to use the object because the application has regained a strong reference to it.

Use long weak references only when necessary as the state of the object is unpredictable after finalization.

Avoid using weak references to small objects because the pointer itself may be as large or larger.

Avoid using weak references as an automatic solution to memory management problems. Instead, develop an effective caching policy for handling your application's objects.




WeakReference Class

The WeakReference type exposes the following members.

  Name Description
Public method Supported by the XNA Framework Supported by Portable Class Library WeakReference(Object) Initializes a new instance of the WeakReference class, referencing the specified object.
Public method Supported by the XNA Framework Supported by Portable Class Library WeakReference(Object, Boolean) Initializes a new instance of the WeakReference class, referencing the specified object and using the specified resurrection tracking.
Protected method WeakReference(SerializationInfo, StreamingContext) Initializes a new instance of the WeakReference class, using deserialized data from the specified serialization and stream objects.
Top
  Name Description
Public property Supported by the XNA Framework Supported by Portable Class Library IsAlive Gets an indication whether the object referenced by the current WeakReference object has been garbage collected.
Public property Supported by the XNA Framework Supported by Portable Class Library Target Gets or sets the object (the target) referenced by the current WeakReference object.
Public property Supported by the XNA Framework Supported by Portable Class Library TrackResurrection Gets an indication whether the object referenced by the current WeakReference object is tracked after it is finalized.
Top
  Name Description
Public method Supported by the XNA Framework Supported by Portable Class Library Equals(Object) Determines whether the specified Object is equal to the current Object. (Inherited from Object.)
Protected method Supported by the XNA Framework Supported by Portable Class Library Finalize Discards the reference to the target represented by the current WeakReference object. (Overrides Object.Finalize().)
Public method Supported by the XNA Framework Supported by Portable Class Library GetHashCode Serves as a hash function for a particular type. (Inherited from Object.)
Public method GetObjectData Populates a SerializationInfo object with all the data needed to serialize the current WeakReference object.
Public method Supported by the XNA Framework Supported by Portable Class Library GetType Gets the Type of the current instance. (Inherited from Object.)
Protected method Supported by the XNA Framework Supported by Portable Class Library MemberwiseClone Creates a shallow copy of the current Object. (Inherited from Object.)
Public method Supported by the XNA Framework Supported by Portable Class Library ToString Returns a string that represents the current object. (Inherited from Object.)
Top

A weak reference allows the garbage collector to collect an object while still allowing an application to access the object. If you need the object, you can still obtain a strong reference to it and prevent it from being collected. For more information about how to use short and long weak references, see Weak References.

The following example demonstrates how you can use weak references to maintain a cache of objects as a resource for an application. The cache is constructed using an IDictionary<TKey, TValue> of WeakReference objects keyed by an index value. The Target property for the WeakReference objects is an object in a byte array that represents data.

The example randomly accesses objects in the cache. If an object is reclaimed for garbage collection, a new data object is regenerated; otherwise, the object is available to access because of the weak reference.

C#
VB
using System;
using System.Collections.Generic;

public class Program
{

    public static void Main()
    {

        // Create the cache.
        int cacheSize = 50;
        Random r = new Random();
        Cache c = new Cache(cacheSize);

        string DataName = "";

        // Randomly access objects in the cache.
        for (int i = 0; i < c.Count; i++)
        {
            int index = r.Next(c.Count);

            // Access the object by
            // getting a property value.
            DataName = c[index].Name;
        }
        // Show results.
        double regenPercent = c.RegenerationCount * 100 / c.Count;
        Console.WriteLine("Cache size: {0}, Regenerated: {1}%", c.Count.ToString(), regenPercent.ToString());

    }
}


public class Cache
{
    // Dictionary to contain the cache.
    static Dictionary<int, WeakReference> _cache;

    // Track the number of times an 
    // object is regenerated.
    int regenCount = 0;   

    public Cache(int count)
    {

        _cache = new Dictionary<int, WeakReference>();

        // Add data objects with a 
        // short weak reference to the cache.
       for (int i = 0; i < count; i++)
        {
            _cache.Add(i, new WeakReference(new Data(i), false));
        }

    }

    // Returns the number of items in the cache.
    public int Count
    {
        get
        {
            return _cache.Count;
        }
    }

    // Returns the number of times an 
    // object had to be regenerated.
    public int RegenerationCount
    {
        get
        {
            return regenCount;
        }
    }

    // Accesses a data object from the cache.
    // If the object was reclaimed for garbage collection,
    // create a new data object at that index location.
    public Data this[int index]
    {
        get
        {
            // Obtain an instance of a data
            // object from the cache of
            // of weak reference objects.
            Data d = _cache[index].Target as Data;
            if (d == null)
            {
                // Object was reclaimed, so generate a new one.
                Console.WriteLine("Regenerate object at {0}: Yes", index.ToString());
                d = new Data(index);
                regenCount++;
            }
            else
            {
                // Object was obtained with the weak reference.
                Console.WriteLine("Regenerate object at {0}: No", index.ToString());
            }

            return d;
       }

    }

}


// This class creates byte arrays to simulate data.
public class Data
{
    private byte[] _data;
    private string _name;

    public Data(int size)
    {
        _data = new byte[size * 1024];
        _name = size.ToString();
    }

    // Simple property.
    public string Name
    {
        get
        {
            return _name;
        }
    }

}

// Example of the last lines of the output:
//
// ...
// Regenerate object at 36: Yes
// Regenerate object at 8: Yes
// Regenerate object at 21: Yes
// Regenerate object at 4: Yes
// Regenerate object at 38: No
// Regenerate object at 7: Yes
// Regenerate object at 2: Yes
// Regenerate object at 43: Yes
// Regenerate object at 38: No
// Cache size: 50, Regenerated: 94%
//



C#中的弱引用(WeakReference)

我们通俗用的都是对象的强引用,若是有强引用存在,GC是不会收受接管对象的。我们能不克不及同时对峙对对象的引用,而又可以让GC须要的时辰收受接管这个对象呢?.NET中供给了WeakReference来实现。弱引用可以让您对峙对对象的引用,同时容许GC在须要时开释对象,收受接管内存。对于那些创建便宜但花费多量内存的对象,即欲望对峙该对象,又要在应用法度须要时应用,同时欲望GC须要时收受接管时,可以推敲应用弱引用。弱引用应用起来很简单,看下面的代码:
Object obj = new Object();
WeakReference wref = new WeakReference( obj );
obj = null;

第一行代码新建了一个新的对象,这里叫它对象A,obj是对对象A的强引用。接着第二行代码新建了一个弱引用对象,参数就是对象A的强引用,第三行代码开释掉对对象A的强引用。这时若是GC进行收受接管,对象A就会被收受接管。
如何在取得对象A的强引用呢?很简单,请看代码2:

Object obj2 = wref.Target;
if( obj2 != null )
{
   // 做你想做的事吧。
}
else
{
// 对象已经被收受接管,若是要用必须新建一个。
}

只要显示的将弱引用的Target属性附值就会获得弱引用所代表对象的一个强引用。不过在应用对象之前要对其可用性进行搜检,因为它可能已经被收受接管了。如 果你获得的是null(VB.NET下为Nothing),注解对象已经被收受接管,不克不及再用了,须要从头分派一个。若是不是null,就可以宁神大胆的用 了。
接下来让我们看WeakReference的别的一个版本,请看代码3:
// public WeakReference(
//   object target,
//   bool trackResurrection
//);


Object obj1 = new Object();

Object obj2 = new Object();

WeakReference wref1 = new WeakReference( obj1, false );

WeakReference wref2 = new WeakReference( obj2, true );

WeakReference的别的一个版本有两个参数,第一个参数和我们前面用的版本的一样。第二个参数让我们看一下他的原型,bool trackResurrection,跟踪复生,是个bool型,就是是否跟踪复生。前面的文章中我提到过须要Finalize的对象在终极开释前会有一 次复生,我们可能可以猜到第二个参数默示的意思了。若是我们第二个参数给false,这个弱引用就是一个short weak reference(短弱引用),当GC收受接管时,发明根中没有这个对象的引用了,就认为这个对象无用,这时短弱引用对这个对象的跟踪到此为止,弱引用的 Target被设置为null。前面的一个参数的机关函数版本新建的弱引用为短弱引用。若是第二个参数给true,这个弱引用就是一个long weak reference(长弱引用)。在对象的Finalize办法没有被履行以前,Target都可用。不过这是对象的某些成员变量也许已经被收受接管,所以使 用起来要想当警惕。
如今让我们看看WeakReference是如何实现的。很显然WeakReference不克不及直接的引用目标对象,WeakReference的 Target属性的get/set是两个函数,从某处查到目标对象的引用返回,而不是我们最常用写的那样直接返回或者设置一个私有变量。GC保护了两个列 表来跟踪两种弱引用的目标对象,在一个 WeakReference对象创建时,它在响应的列表中找到一个地位,将目标对象的引用放入,很显然,这两个列表不是根的一项目组。在GC进行内存收受接管的 时辰,若是要收受接管某一个对象,会搜检弱引用的列表,若是保存着这个对象的引用,则将其设为null。 
public class AspPage : Page
{
private static ArrayList __ENCList = new ArrayList();

   [DebuggerNonUserCode]
        public AspPage()
        {
            base.Load += new EventHandler(this.Page_Load);
            ArrayList list = __ENCList;
            lock (list)
            {
                __ENCList.Add(new WeakReference(this));
            }
        }

}



<think>首先,用户的问题是:“我想在C#中实现弱引用并使用RaisePropertyChanged请问C#weakreferenceimplementationwithINotifyPropertyChangedandRaisePropertyChanged”。这是在C#中实现弱引用(WeakReference)与INotifyPropertyChanged接口和RaisePropertyChanged方法结合使用。我需要回顾系统级指令:-所有行内数学表达式使用$...$格式。-独立公式使用$$...$$格式并单独成段。-LaTeX语法正确。-使用中文回答。-生成相关问题。-在引用的段落末尾自然地添加引用标识,例如[^1]。用户可见层的指令:-回答结构清晰,帮助用户逐步解决问题。-尽量保证回答真实可靠。参考站内引用:-[^1]:解释C#中的弱引用(WeakReference)。-[^2]:讨论Java中的WeakHashMap。-[^3]:关于C++智能指针。-[^4]:iOS中的弱引用错误。-[^5]:iOS闪退问题与弱引用相关。这些引用主要涉及弱引用的概念和在不同语言中的实现,但用户的问题是针对C#的。我需要聚焦于C#的实现,特别是与INotifyPropertyChanged结合。关键概念:-**弱引用(WeakReference)**:在C#中,允许对象被垃圾回收器回收,即使有引用指向它,但不会阻止回收。-**INotifyPropertyChanged**:一个接口,用于在属性更改时通知绑定(如在WPF或MVVM模式中)。-**RaisePropertyChanged**:通常是一个方法,用于触发PropertyChanged事件。用户想实现弱引用,同时使用INotifyPropertyChanged。这可能用于避免内存泄漏,特别是在事件处理或数据绑定场景中。步骤:1.**解释弱引用的基本实现**:使用WeakReference类。2.**结合INotifyPropertyChanged**:创建一个类实现INotifyPropertyChanged,并在属性更改时使用弱引用来引用对象。3.**使用RaisePropertyChanged**:在属性设置器中调用RaisePropertyChanged。4.**处理弱引用**:确保当对象被回收时,不会引发异常。回答结构:-**引言**:简要解释问题和解决方案。-**步骤实现**:-创建一个类实现INotifyPropertyChanged。-使用WeakReference来引用可能被回收的对象。-在属性更改时,检查弱引用是否存活,然后调用RaisePropertyChanged。-**代码示例**:提供C#代码示例。-**注意事项**:讨论潜在问题,如对象被回收时的处理。-**生成相关问题**:在末尾添加相关问题。生成相关问题:1.如何在C#中使用弱引用避免内存泄漏?2.INotifyPropertyChanged在MVVM模式中的作用是什么?3.弱引用在其他语言(如Java)中如何实现?确保回答真实可靠:基于C#文档和最佳实践。代码示例:需要包含WeakReference和INotifyPropertyChanged的实现。</think>### C#弱引用与INotifyPropertyChanged的实现指南 在C#中,弱引用(`WeakReference`)允许对象被垃圾回收器(GC)回收,即使有引用指向它,这有助于避免内存泄漏。结合`INotifyPropertyChanged`接口和`RaisePropertyChanged`方法,常用于MVVM模式(如WPF或Xamarin开发),以实现属性更改通知。下面我将逐步解释如何实现这种结合,确保结构清晰、可靠。 #### 1. **核心概念回顾** - **弱引用(WeakReference)**:创建一个对对象的引用,但不会阻止GC回收该对象。通过`WeakReference`类实现,使用`TryGetTarget`方法检查对象是否存活[^1]。 - **INotifyPropertyChanged**:接口定义`PropertyChanged`事件,用于在属性值更改时通知UI绑定更新。 - **RaisePropertyChanged**:一个辅助方法,用于触发`PropertyChanged`事件,通常在属性设置器中调用。 #### 2. **实现步骤** 以下是完整的实现方案,分为三个部分:定义弱引用包装器、实现INotifyPropertyChanged、结合使用两者。 ##### 步骤1: 创建弱引用包装器类 首先,定义一个泛型类`WeakReference<T>`,用于包装对象并提供安全访问。这可以避免直接使用`WeakReference`时的冗余代码。 ```csharp using System; public class WeakReference<T> where T : class { private readonly WeakReference _weakReference; public WeakReference(T target) { _weakReference = new WeakReference(target); } public bool TryGetTarget(out T target) { if (_weakReference.IsAlive) { target = (T)_weakReference.Target; return true; } target = null; return false; } } ``` - **说明**:此类封装了标准`WeakReference`,`TryGetTarget`检查对象是否被回收。如果对象存活,返回true并获取目标;否则返回false[^1]。 ##### 步骤2: 实现INotifyPropertyChanged和RaisePropertyChanged 创建一个ViewModel基类,实现`INotifyPropertyChanged`接口,并包含`RaisePropertyChanged`方法。 ```csharp using System.ComponentModel; public abstract class ViewModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected virtual void RaisePropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } ``` - **说明**:`RaisePropertyChanged`方法安全地触发事件(使用`?.`避免空引用异常)。在属性设置器中调用此方法以通知UI更新。 ##### 步骤3: 结合弱引用和属性更改通知 在具体ViewModel中,使用`WeakReference<T>`引用其他对象(如依赖项),并在属性更改时检查弱引用是否有效。 ```csharp public class UserViewModel : ViewModelBase { private string _name; private WeakReference<ExternalService> _serviceRef; // 弱引用外部服务 public string Name { get => _name; set { if (_name != value) { _name = value; RaisePropertyChanged(nameof(Name)); // 通知UI更新 // 检查弱引用对象是否存活 if (_serviceRef != null && _serviceRef.TryGetTarget(out var service)) { service.OnNameChanged(value); // 安全调用方法 } } } } public UserViewModel(ExternalService service) { _serviceRef = new WeakReference<ExternalService>(service); } } // 示例依赖类 public class ExternalService { public void OnNameChanged(string name) { Console.WriteLine($"Name changed to: {name}"); } } ``` - **关键点**: - 在`Name`属性的设置器中,调用`RaisePropertyChanged`后,使用`_serviceRef.TryGetTarget`检查`ExternalService`实例是否被回收。 - 如果对象存活(返回true),则执行操作(如`OnNameChanged`);如果被回收(返回false),则忽略操作,避免异常。 - 这确保了即使`ExternalService`被GC回收,也不会导致内存泄漏或崩溃。 #### 3. **注意事项和最佳实践** - **避免内存泄漏**:弱引用适用于缓存、事件处理或跨组件引用。如果对象生命周期短,弱引用可防止因强引用导致的泄漏[^1]。 - **性能考虑**:频繁检查`TryGetTarget`可能增加开销。仅在必要时使用,例如在属性更改或事件触发时。 - **错误处理**:当弱引用对象被回收时,`TryGetTarget`返回false,应优雅处理(如跳过操作或重新初始化引用)。 - **与事件结合**:在事件处理中,使用弱引用可防止订阅者未被注销时泄漏。例如: ```csharp public class EventHandlerWrapper { private WeakReference<Action> _handlerRef; public EventHandlerWrapper(Action handler) { _handlerRef = new WeakReference<Action>(handler); } public void InvokeIfAlive() { if (_handlerRef.TryGetTarget(out var handler)) { handler.Invoke(); } } } ``` - **iOS/跨平台注意**:在Xamarin等跨平台开发中,弱引用行为一致,但需确保Objective-C互操作设置正确(如避免手动引用计数错误[^4])。 #### 4. **为什么这样设计可靠?** - 基于C#官方文档:`WeakReference`是.NET标准库的一部分,确保GC兼容性[^1]。 - MVVM模式最佳实践:`RaisePropertyChanged`是通知绑定的标准方式,结合弱引用增强健壮性。 - 真实场景验证:此模式常用于WPF、Xamarin应用,处理UI和后台服务的松耦合。 通过上述实现,您可以安全地在C#中使用弱引用管理对象生命周期,同时利用`INotifyPropertyChanged`实现响应式UI更新。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值