1 // ==++==
2 //
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 //
5 // ==--==
6 /*============================================================
7 **
8 ** Class: WeakReference<T>
9 **
10 ** Purpose: A wrapper for establishing a WeakReference to a generic type.
11 **
12 ===========================================================*/
13 namespace System
14 {
15     using System;
16     using System.Runtime.Serialization;
17     using System.Security;
18     using System.Runtime;
19     using System.Runtime.CompilerServices;
20     using System.Runtime.Versioning;
21     using System.Diagnostics.Contracts;
22 
23     [Serializable]
24     // This class is sealed to mitigate security issues caused by Object::MemberwiseClone.
25     public sealed class WeakReference<T> : ISerializable where T : class
26     {
27         // If you fix bugs here, please fix them in WeakReference at the same time.
28 
29         // This field is not a regular GC handle. It can have a special values that are used to prevent ----s between setting the target and finalization.
30         internal IntPtr m_handle;
31 
32         // Creates a new WeakReference that keeps track of target.
33         // Assumes a Short Weak Reference (ie TrackResurrection is false.)
34         //
WeakReference(T target)35         public WeakReference(T target)
36             : this(target, false)
37         {
38         }
39 
40         //Creates a new WeakReference that keeps track of target.
41         //
WeakReference(T target, bool trackResurrection)42         public WeakReference(T target, bool trackResurrection)
43         {
44             Create(target, trackResurrection);
45         }
46 
WeakReference(SerializationInfo info, StreamingContext context)47         internal WeakReference(SerializationInfo info, StreamingContext context)
48         {
49             if (info == null) {
50                 throw new ArgumentNullException("info");
51             }
52             Contract.EndContractBlock();
53 
54             T target = (T)info.GetValue("TrackedObject", typeof(T));
55             bool trackResurrection = info.GetBoolean("TrackResurrection");
56 
57             Create(target, trackResurrection);
58         }
59 
60         //
61         // We are exposing TryGetTarget instead of a simple getter to avoid a common problem where people write incorrect code like:
62         //
63         //      WeakReference ref = ...;
64         //      if (ref.Target != null)
65         //          DoSomething(ref.Target)
66         //
67         [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
TryGetTarget(out T target)68         public bool TryGetTarget(out T target)
69         {
70             // Call the worker method that has more performant but less user friendly signature.
71             T o = this.Target;
72             target = o;
73             return o != null;
74         }
75 
SetTarget(T target)76         public void SetTarget(T target)
77         {
78             this.Target = target;
79         }
80 
81         // This is property for better debugging experience (VS debugger shows values of properties when you hover over the variables)
82         private extern T Target
83         {
84             [ResourceExposure(ResourceScope.None)]
85             [MethodImplAttribute(MethodImplOptions.InternalCall)]
86             [SecuritySafeCritical]
87             get;
88             [ResourceExposure(ResourceScope.None)]
89             [MethodImplAttribute(MethodImplOptions.InternalCall)]
90             [SecuritySafeCritical]
91             set;
92         }
93 
94         // Free all system resources associated with this reference.
95         //
96         // Note: The WeakReference<T> finalizer is not usually run, but
97         // treated specially in gc.cpp's ScanForFinalization
98         // This is needed for subclasses deriving from WeakReference<T>, however.
99         // Additionally, there may be some cases during shutdown when we run this finalizer.
100         [ResourceExposure(ResourceScope.None)]
101         [MethodImplAttribute(MethodImplOptions.InternalCall)]
102         [SecuritySafeCritical]
~WeakReference()103         extern ~WeakReference();
104 
105         [SecurityCritical]
GetObjectData(SerializationInfo info, StreamingContext context)106         public void GetObjectData(SerializationInfo info, StreamingContext context)
107         {
108             if (info == null) {
109                 throw new ArgumentNullException("info");
110             }
111             Contract.EndContractBlock();
112 
113             info.AddValue("TrackedObject", this.Target, typeof(T));
114             info.AddValue("TrackResurrection", IsTrackResurrection());
115         }
116 
117         [ResourceExposure(ResourceScope.None)]
118         [MethodImplAttribute(MethodImplOptions.InternalCall)]
119         [SecuritySafeCritical]
Create(T target, bool trackResurrection)120         private extern void Create(T target, bool trackResurrection);
121 
122         [ResourceExposure(ResourceScope.None)]
123         [MethodImplAttribute(MethodImplOptions.InternalCall)]
124         [SecuritySafeCritical]
IsTrackResurrection()125         private extern bool IsTrackResurrection();
126     }
127 }
128