[{"data":1,"prerenderedAt":861},["ShallowReactive",2],{"blog:2006:equatable_weak_references":3,"blogMore-Development":847,"comments-equatable_weak_references":860},{"id":4,"title":5,"body":6,"category":829,"commentCount":830,"date":831,"description":832,"excerpt":833,"extension":834,"filenames":835,"hidden":836,"image":835,"meta":837,"minutes":136,"navigation":139,"path":838,"seo":839,"showCategory":835,"stem":840,"tags":841,"updated":835,"url":844,"wordCount":845,"__hash__":846},"content\u002Fblog\u002F2006\u002Fequatable_weak_references.md","Equatable Weak References",{"type":7,"value":8,"toc":827},"minimark",[9,31,45,57,60,63,66,76,79,82,88,817,823],[10,11,12,13,21,22,30],"p",{},"In a previous post I described a ",[14,15,17],"a",{"href":16},"\u002Fblog\u002F2006\u002Fimplementingweakreferencet\u002F",[18,19,20],"code",{},"WeakReference\u003CT>"," class for providing strongly-typed ",[14,23,27],{"href":24,"rel":25},"https:\u002F\u002Fmsdn2.microsoft.com\u002Fen-us\u002Flibrary\u002Fsystem.weakreference.aspx",[26],"nofollow",[18,28,29],{},"WeakReference"," objects.",[32,33,34],"blockquote",{},[10,35,36,37],{},"GitHub has the ",[14,38,41,42],{"href":39,"rel":40},"https:\u002F\u002Fgithub.com\u002Fdamieng\u002FDamienGKit\u002Fblob\u002Fmaster\u002FCSharp\u002FDamienG.Library\u002FSystem\u002FEquatableWeakReference.cs",[26],"latest version of ",[18,43,44],{},"EquatableWeakReference\u003CT>",[10,46,47,48,50,51,53,54,56],{},"One problem with the previous ",[18,49,20],{}," class is being able to use and find it within the various collection classes. This is because one ",[18,52,20],{}," is not equal to another ",[18,55,20],{}," class.",[10,58,59],{},"Overriding the Equals method fixes this problem at first glance however also reveals another issue.",[10,61,62],{},"If you override Equals you should also override the GetHashCode method so that two objects that equal each other return the same hash code. This is because some of the collection classes use hash codes to efficiently lookup items within their collection.",[10,64,65],{},"Normally a hash code would be calculated from the various data items that comprise the class but in our case we really only have one to go on: the Target object itself. This raises two more issues:",[67,68,69,73],"ol",{},[70,71,72],"li",{},"The hash code should not change over the objects lifetime, which is difficult when your Target object can be changed.",[70,74,75],{},"The hash code should be stored because the Target object might well be collected by the GC, and after all that’s what this class is all about.",[10,77,78],{},"This doesn’t leave us with many choices at all.",[10,80,81],{},"We must grab the hash code from the Target object within our constructor and store it for subsequent retrieval.",[10,83,84,85,87],{},"Here is ",[18,86,44],{}," with the usual disclaimers as to it’s suitability for any purpose.",[89,90,95],"pre",{"className":91,"code":92,"language":93,"meta":94,"style":94},"language-csharp shiki shiki-themes everforest-light dracula","using System;\nusing System.Runtime.InteropServices;\n\npublic class EquatableWeakReference\u003CT> : IEquatable\u003CEquatableWeakReference\u003CT>>, IDisposable where T : class\n{\n    protected GCHandle handle;\n    protected int hashCode;\n\n    public EquatableWeakReference(T target) {\n        if (target == null)\n            throw new ArgumentNullException(\"target\");\n        hashCode = target.GetHashCode();\n        InitializeHandle(target);\n    }\n\n    protected virtual void InitializeHandle(T target) {\n        handle = GCHandle.Alloc(target, GCHandleType.Weak);\n    }\n\n    ~EquatableWeakReference() {\n        Dispose();\n    }\n\n    public void Dispose() {\n        handle.Free();\n        GC.SuppressFinalize(this);\n    }\n\n    public virtual bool IsAlive {\n        get { return (handle.Target != null); }\n    }\n\n    public virtual T Target {\n        get {\n            object o = handle.Target;\n            if ((o == null) || (!(o is T)))\n               return null;\n            else\n               return (T)o;\n            }\n    }\n\n    public override bool Equals(object other) {\n        if (other is EquatableWeakReference\u003CT>)\n            return Equals((EquatableWeakReference\u003CT>)other);\n        else\n            return false;\n    }\n\n    public override int GetHashCode() {\n        return hashCode;\n    }\n\n    public bool Equals(EquatableWeakReference\u003CT> other) {\n        return ReferenceEquals(other.Target, this.Target);\n    }\n}\n","csharp","",[18,96,97,114,134,141,196,202,214,226,231,252,271,298,316,325,331,336,358,381,386,391,402,410,415,420,432,443,460,465,470,483,509,514,519,531,539,557,593,603,609,621,627,632,637,660,679,699,705,715,720,725,739,747,752,757,782,806,811],{"__ignoreMap":94},[98,99,102,106,110],"span",{"class":100,"line":101},"line",1,[98,103,105],{"class":104},"smiwp","using",[98,107,109],{"class":108},"sjYfO"," System",[98,111,113],{"class":112},"s6Vpi",";\n",[98,115,117,119,121,124,127,129,132],{"class":100,"line":116},2,[98,118,105],{"class":104},[98,120,109],{"class":108},[98,122,123],{"class":112},".",[98,125,126],{"class":108},"Runtime",[98,128,123],{"class":112},[98,130,131],{"class":108},"InteropServices",[98,133,113],{"class":112},[98,135,137],{"class":100,"line":136},3,[98,138,140],{"emptyLinePlaceholder":139},true,"\n",[98,142,144,148,151,155,158,162,165,169,171,174,176,178,181,184,187,190,193],{"class":100,"line":143},4,[98,145,147],{"class":146},"s9HRq","public",[98,149,150],{"class":104}," class",[98,152,154],{"class":153},"sPLAf"," EquatableWeakReference",[98,156,157],{"class":112},"\u003C",[98,159,161],{"class":160},"sAO9U","T",[98,163,164],{"class":112},"> : ",[98,166,168],{"class":167},"snuxY","IEquatable",[98,170,157],{"class":112},[98,172,173],{"class":167},"EquatableWeakReference",[98,175,157],{"class":112},[98,177,161],{"class":167},[98,179,180],{"class":112},">>, ",[98,182,183],{"class":167},"IDisposable",[98,185,186],{"class":146}," where",[98,188,189],{"class":160}," T",[98,191,192],{"class":112}," : ",[98,194,195],{"class":104},"class\n",[98,197,199],{"class":100,"line":198},5,[98,200,201],{"class":112},"{\n",[98,203,205,208,211],{"class":100,"line":204},6,[98,206,207],{"class":146},"    protected",[98,209,210],{"class":167}," GCHandle",[98,212,213],{"class":112}," handle;\n",[98,215,217,219,223],{"class":100,"line":216},7,[98,218,207],{"class":146},[98,220,222],{"class":221},"sXAHl"," int",[98,224,225],{"class":112}," hashCode;\n",[98,227,229],{"class":100,"line":228},8,[98,230,140],{"emptyLinePlaceholder":139},[98,232,234,237,240,243,245,249],{"class":100,"line":233},9,[98,235,236],{"class":146},"    public",[98,238,154],{"class":239},"sS4Kt",[98,241,242],{"class":112},"(",[98,244,161],{"class":167},[98,246,248],{"class":247},"s7cAX"," target",[98,250,251],{"class":112},") {\n",[98,253,255,258,261,264,268],{"class":100,"line":254},10,[98,256,257],{"class":104},"        if",[98,259,260],{"class":112}," (target ",[98,262,263],{"class":146},"==",[98,265,267],{"class":266},"s3Ipq"," null",[98,269,270],{"class":112},")\n",[98,272,274,277,280,283,285,289,293,295],{"class":100,"line":273},11,[98,275,276],{"class":104},"            throw",[98,278,279],{"class":104}," new",[98,281,282],{"class":167}," ArgumentNullException",[98,284,242],{"class":112},[98,286,288],{"class":287},"sciFF","\"",[98,290,292],{"class":291},"sJQOs","target",[98,294,288],{"class":287},[98,296,297],{"class":112},");\n",[98,299,301,304,307,310,313],{"class":100,"line":300},12,[98,302,303],{"class":112},"        hashCode ",[98,305,306],{"class":146},"=",[98,308,309],{"class":112}," target.",[98,311,312],{"class":239},"GetHashCode",[98,314,315],{"class":112},"();\n",[98,317,319,322],{"class":100,"line":318},13,[98,320,321],{"class":239},"        InitializeHandle",[98,323,324],{"class":112},"(target);\n",[98,326,328],{"class":100,"line":327},14,[98,329,330],{"class":112},"    }\n",[98,332,334],{"class":100,"line":333},15,[98,335,140],{"emptyLinePlaceholder":139},[98,337,339,341,344,347,350,352,354,356],{"class":100,"line":338},16,[98,340,207],{"class":146},[98,342,343],{"class":146}," virtual",[98,345,346],{"class":221}," void",[98,348,349],{"class":239}," InitializeHandle",[98,351,242],{"class":112},[98,353,161],{"class":167},[98,355,248],{"class":247},[98,357,251],{"class":112},[98,359,361,364,366,369,372,375,379],{"class":100,"line":360},17,[98,362,363],{"class":112},"        handle ",[98,365,306],{"class":146},[98,367,368],{"class":112}," GCHandle.",[98,370,371],{"class":239},"Alloc",[98,373,374],{"class":112},"(target, GCHandleType.",[98,376,378],{"class":377},"sSKRk","Weak",[98,380,297],{"class":112},[98,382,384],{"class":100,"line":383},18,[98,385,330],{"class":112},[98,387,389],{"class":100,"line":388},19,[98,390,140],{"emptyLinePlaceholder":139},[98,392,394,397,399],{"class":100,"line":393},20,[98,395,396],{"class":112},"    ~",[98,398,173],{"class":239},[98,400,401],{"class":112},"() {\n",[98,403,405,408],{"class":100,"line":404},21,[98,406,407],{"class":239},"        Dispose",[98,409,315],{"class":112},[98,411,413],{"class":100,"line":412},22,[98,414,330],{"class":112},[98,416,418],{"class":100,"line":417},23,[98,419,140],{"emptyLinePlaceholder":139},[98,421,423,425,427,430],{"class":100,"line":422},24,[98,424,236],{"class":146},[98,426,346],{"class":221},[98,428,429],{"class":239}," Dispose",[98,431,401],{"class":112},[98,433,435,438,441],{"class":100,"line":434},25,[98,436,437],{"class":112},"        handle.",[98,439,440],{"class":239},"Free",[98,442,315],{"class":112},[98,444,446,449,452,454,458],{"class":100,"line":445},26,[98,447,448],{"class":112},"        GC.",[98,450,451],{"class":239},"SuppressFinalize",[98,453,242],{"class":112},[98,455,457],{"class":456},"sKO3f","this",[98,459,297],{"class":112},[98,461,463],{"class":100,"line":462},27,[98,464,330],{"class":112},[98,466,468],{"class":100,"line":467},28,[98,469,140],{"emptyLinePlaceholder":139},[98,471,473,475,477,480],{"class":100,"line":472},29,[98,474,236],{"class":146},[98,476,343],{"class":146},[98,478,479],{"class":221}," bool",[98,481,482],{"class":112}," IsAlive {\n",[98,484,486,489,492,495,498,501,504,506],{"class":100,"line":485},30,[98,487,488],{"class":221},"        get",[98,490,491],{"class":112}," { ",[98,493,494],{"class":104},"return",[98,496,497],{"class":112}," (handle.",[98,499,500],{"class":377},"Target",[98,502,503],{"class":146}," !=",[98,505,267],{"class":266},[98,507,508],{"class":112},"); }\n",[98,510,512],{"class":100,"line":511},31,[98,513,330],{"class":112},[98,515,517],{"class":100,"line":516},32,[98,518,140],{"emptyLinePlaceholder":139},[98,520,522,524,526,528],{"class":100,"line":521},33,[98,523,236],{"class":146},[98,525,343],{"class":146},[98,527,189],{"class":167},[98,529,530],{"class":112}," Target {\n",[98,532,534,536],{"class":100,"line":533},34,[98,535,488],{"class":221},[98,537,538],{"class":112}," {\n",[98,540,542,545,548,550,553,555],{"class":100,"line":541},35,[98,543,544],{"class":221},"            object",[98,546,547],{"class":112}," o ",[98,549,306],{"class":146},[98,551,552],{"class":112}," handle.",[98,554,500],{"class":377},[98,556,113],{"class":112},[98,558,560,563,566,568,570,573,576,579,582,585,588,590],{"class":100,"line":559},36,[98,561,562],{"class":104},"            if",[98,564,565],{"class":112}," ((o ",[98,567,263],{"class":146},[98,569,267],{"class":266},[98,571,572],{"class":112},") ",[98,574,575],{"class":146},"||",[98,577,578],{"class":112}," (",[98,580,581],{"class":146},"!",[98,583,584],{"class":112},"(o ",[98,586,587],{"class":104},"is",[98,589,189],{"class":167},[98,591,592],{"class":112},")))\n",[98,594,596,599,601],{"class":100,"line":595},37,[98,597,598],{"class":104},"               return",[98,600,267],{"class":266},[98,602,113],{"class":112},[98,604,606],{"class":100,"line":605},38,[98,607,608],{"class":104},"            else\n",[98,610,612,614,616,618],{"class":100,"line":611},39,[98,613,598],{"class":104},[98,615,578],{"class":112},[98,617,161],{"class":167},[98,619,620],{"class":112},")o;\n",[98,622,624],{"class":100,"line":623},40,[98,625,626],{"class":112},"            }\n",[98,628,630],{"class":100,"line":629},41,[98,631,330],{"class":112},[98,633,635],{"class":100,"line":634},42,[98,636,140],{"emptyLinePlaceholder":139},[98,638,640,642,645,647,650,652,655,658],{"class":100,"line":639},43,[98,641,236],{"class":146},[98,643,644],{"class":146}," override",[98,646,479],{"class":221},[98,648,649],{"class":239}," Equals",[98,651,242],{"class":112},[98,653,654],{"class":221},"object",[98,656,657],{"class":247}," other",[98,659,251],{"class":112},[98,661,663,665,668,670,672,674,676],{"class":100,"line":662},44,[98,664,257],{"class":104},[98,666,667],{"class":112}," (other ",[98,669,587],{"class":104},[98,671,154],{"class":167},[98,673,157],{"class":112},[98,675,161],{"class":167},[98,677,678],{"class":112},">)\n",[98,680,682,685,687,690,692,694,696],{"class":100,"line":681},45,[98,683,684],{"class":104},"            return",[98,686,649],{"class":239},[98,688,689],{"class":112},"((",[98,691,173],{"class":167},[98,693,157],{"class":112},[98,695,161],{"class":167},[98,697,698],{"class":112},">)other);\n",[98,700,702],{"class":100,"line":701},46,[98,703,704],{"class":104},"        else\n",[98,706,708,710,713],{"class":100,"line":707},47,[98,709,684],{"class":104},[98,711,712],{"class":266}," false",[98,714,113],{"class":112},[98,716,718],{"class":100,"line":717},48,[98,719,330],{"class":112},[98,721,723],{"class":100,"line":722},49,[98,724,140],{"emptyLinePlaceholder":139},[98,726,728,730,732,734,737],{"class":100,"line":727},50,[98,729,236],{"class":146},[98,731,644],{"class":146},[98,733,222],{"class":221},[98,735,736],{"class":239}," GetHashCode",[98,738,401],{"class":112},[98,740,742,745],{"class":100,"line":741},51,[98,743,744],{"class":104},"        return",[98,746,225],{"class":112},[98,748,750],{"class":100,"line":749},52,[98,751,330],{"class":112},[98,753,755],{"class":100,"line":754},53,[98,756,140],{"emptyLinePlaceholder":139},[98,758,760,762,764,766,768,770,772,774,777,780],{"class":100,"line":759},54,[98,761,236],{"class":146},[98,763,479],{"class":221},[98,765,649],{"class":239},[98,767,242],{"class":112},[98,769,173],{"class":167},[98,771,157],{"class":112},[98,773,161],{"class":167},[98,775,776],{"class":112},"> ",[98,778,779],{"class":247},"other",[98,781,251],{"class":112},[98,783,785,787,790,793,795,798,800,802,804],{"class":100,"line":784},55,[98,786,744],{"class":104},[98,788,789],{"class":239}," ReferenceEquals",[98,791,792],{"class":112},"(other.",[98,794,500],{"class":377},[98,796,797],{"class":112},", ",[98,799,457],{"class":456},[98,801,123],{"class":112},[98,803,500],{"class":377},[98,805,297],{"class":112},[98,807,809],{"class":100,"line":808},56,[98,810,330],{"class":112},[98,812,814],{"class":100,"line":813},57,[98,815,816],{"class":112},"}\n",[10,818,819],{},[820,821,822],"em",{},"[)amien",[824,825,826],"style",{},"html pre.shiki code .smiwp, html code.shiki .smiwp{--shiki-default:#F85552;--shiki-dark:#FF79C6}html pre.shiki code .sjYfO, html code.shiki .sjYfO{--shiki-default:#DF69BA;--shiki-default-font-style:inherit;--shiki-dark:#8BE9FD;--shiki-dark-font-style:italic}html pre.shiki code .s6Vpi, html code.shiki .s6Vpi{--shiki-default:#5C6A72;--shiki-dark:#F8F8F2}html pre.shiki code .s9HRq, html code.shiki .s9HRq{--shiki-default:#F57D26;--shiki-dark:#FF79C6}html pre.shiki code .sPLAf, html code.shiki .sPLAf{--shiki-default:#3A94C5;--shiki-dark:#8BE9FD}html pre.shiki code .sAO9U, html code.shiki .sAO9U{--shiki-default:#3A94C5;--shiki-default-font-style:inherit;--shiki-dark:#FFB86C;--shiki-dark-font-style:italic}html pre.shiki code .snuxY, html code.shiki .snuxY{--shiki-default:#3A94C5;--shiki-default-font-style:inherit;--shiki-dark:#8BE9FD;--shiki-dark-font-style:italic}html pre.shiki code .sXAHl, html code.shiki .sXAHl{--shiki-default:#3A94C5;--shiki-dark:#FF79C6}html pre.shiki code .sS4Kt, html code.shiki .sS4Kt{--shiki-default:#8DA101;--shiki-dark:#50FA7B}html pre.shiki code .s7cAX, html code.shiki .s7cAX{--shiki-default:#5C6A72;--shiki-default-font-style:inherit;--shiki-dark:#FFB86C;--shiki-dark-font-style:italic}html pre.shiki code .s3Ipq, html code.shiki .s3Ipq{--shiki-default:#DF69BA;--shiki-dark:#BD93F9}html pre.shiki code .sciFF, html code.shiki .sciFF{--shiki-default:#8DA101;--shiki-dark:#E9F284}html pre.shiki code .sJQOs, html code.shiki .sJQOs{--shiki-default:#8DA101;--shiki-dark:#F1FA8C}html pre.shiki code .sSKRk, html code.shiki .sSKRk{--shiki-default:#35A77C;--shiki-dark:#F8F8F2}html pre.shiki code .sKO3f, html code.shiki .sKO3f{--shiki-default:#DF69BA;--shiki-default-font-style:inherit;--shiki-dark:#BD93F9;--shiki-dark-font-style:italic}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":94,"searchDepth":116,"depth":116,"links":828},[],"Development",0,"2006-08-28T07:06:56+00:00","In a previous post I described a WeakReference\u003CT> class for providing strongly-typed WeakReference objects.","[object Object]","md",null,false,{},"\u002Fblog\u002F2006\u002Fequatable_weak_references",{"title":5,"description":832},"blog\u002F2006\u002Fequatable_weak_references",[842,843],".NET","C#","\u002Fblog\u002F2006\u002Fequatable_weak_references\u002F",573,"CVg4-6vfuqohIjRpY1QCryH-x48HnaZpWLe7U7Am6dI",[848,852,856],{"title":849,"date":850,"url":851},"Transactions in the MongoDB EF Core Provider","2025-10-25","\u002Fblog\u002F2025\u002Fmongodb-explicit-transactions\u002F",{"title":853,"date":854,"url":855},"Queryable Encryption with the MongoDB EF Core Provider","2025-09-22","\u002Fblog\u002F2025\u002Fmongodb-queryable-encryption\u002F",{"title":857,"date":858,"url":859},"Lazy Loading with EF Core Proxies","2025-04-02","\u002Fblog\u002F2025\u002Fef-proxies\u002F",[],1780900533030]