{"id":102950,"date":"2019-10-02T07:00:00","date_gmt":"2019-10-02T14:00:00","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/oldnewthing\/?p=102950"},"modified":"2019-10-03T13:47:35","modified_gmt":"2019-10-03T20:47:35","slug":"20191002-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20191002-00\/?p=102950","title":{"rendered":"The default value for a XAML dependency property should be immutable"},"content":{"rendered":"<p>When you define a custom XAML dependency property, one of the things you do is specify the default value. You can do this by providing the default value directly:<\/p>\n<pre>DependencyProperty.Register(\"MyProperty\",\r\n    propertyType, ownerType,\r\n    new PropertyMetadata(defaultValue));\r\n<\/pre>\n<p>UWP XAML also lets you provide a callback that produces the default value:<\/p>\n<pre>DependencyProperty.Register(\"MyProperty\",\r\n    propertyType, ownerType,\r\n    PropertyMetadata.Create(createDefaultValue));\r\n<\/pre>\n<p>What&#8217;s not entirely obvious is that the default value statically provided at registration or provided dynamically at runtime should be an immutable object, if you know what&#8217;s good for you.<\/p>\n<p>The default value of a dependency property is the value used if no value has been set: Nobody has explicitly assigned a value, there is no active binding, no active animation, no active style, nothing.<\/p>\n<p>When XAML needs the default value of the dependency property, it uses the static default property, if provided. Otherwise, it calls the <code>create\u00adDefault\u00adValue<\/code> delegate, if provided. Otherwise, it uses <code>null<\/code>.<\/p>\n<p>For concreteness, let&#8217;s say that we have a <code>Widget<\/code> object and a dependency property of type <code>Light<\/code>.<\/p>\n<p>Let&#8217;s first look at the case where you provide a static mutable value for the default value of the dependency property.<\/p>\n<pre>\/\/ Code in italics is wrong.\r\nclass Light\r\n{\r\n  public Color Color { get; set; }; \/\/ read-write property\r\n}\r\n\r\nclass Widget\r\n{\r\n ...\r\n\r\n public Widget()\r\n {\r\n  InitializeComponent();\r\n }\r\n\r\n \/\/ The default is a red light.\r\n public static readonly DependencyProperty FrontLightProperty =\r\n    DependencyProperty.Register(\"FrontLight\",\r\n    typeof(Light), typeof(Widget),\r\n    <i>new PropertyMetadata(new Light { Color = Color.Red })<\/i>);\r\n\r\n \/\/ Provide convenient access to the dependency property.\r\n public Light FrontLight {\r\n  get =&gt; (Light)GetValue(FrontLightProperty);\r\n  set =&gt; SetValue(FrontLightProperty, value);\r\n }\r\n}\r\n\r\nvoid Example()\r\n{\r\n  var a = new Widget();\r\n  var b = new Widget();\r\n\r\n  var aColor = a.FrontLight.Color; \/\/ aColor is Red\r\n  var bColor = b.FrontLight.Color; \/\/ bColor is Red\r\n\r\n  a.FrontLight.Color = Color.Blue;\r\n  var bColor2 = b.FrontLight.Color; \/\/ bColor2 is Blue (!)\r\n}\r\n<\/pre>\n<p>Since no custom value of <code>Front\u00adLight<\/code> has been set, <code>a<\/code><code>.FrontLight<\/code> and <code>b<\/code><code>.FrontLight<\/code> both contain the default value, which is the red <code>Light<\/code> provided to the <code>Property\u00adMetadata<\/code> constructor.<\/p>\n<p>But since <code>Light<\/code> objects are mutable, the properties of that default value can be changed, and those changes are visible to both <code>a<\/code> and <code>b<\/code>, because <code>a<\/code><code>.FrontLight<\/code> and <code>b<\/code><code>.FrontLight<\/code> are the same object.<\/p>\n<p>&#8220;Aha,&#8221; you may think, &#8220;that&#8217;s where the callback version comes in handy.&#8221; If you set up the callback to produce a unique object, then <code>a<\/code><code>.FrontLight<\/code> and <code>b<\/code><code>.FrontLight<\/code> will be different objects, and they won&#8217;t affect each other.<\/p>\n<pre>\/\/ Code in italics is wrong.\r\nclass Widget\r\n{\r\n ...\r\n\r\n public Widget()\r\n {\r\n  InitializeComponent();\r\n }\r\n\r\n \/\/ The default is a red light.\r\n public static readonly DependencyProperty FrontLightProperty =\r\n    DependencyProperty.Register(\"FrontLight\",\r\n    typeof(Light), typeof(Widget),\r\n    <span style=\"color: blue;\"><i>PropertyMetadata.Create(() =&gt; new Light { Color = Color.Red })<\/i><\/span>);\r\n\r\n \/\/ Provide convenient access to the dependency property.\r\n public Light FrontLight {\r\n  get =&gt; (Light)GetValue(FrontLightProperty);\r\n  set =&gt; SetValue(FrontLightProperty, value);\r\n }\r\n}\r\n\r\nvoid Example()\r\n{\r\n  var aColor = a.FrontLight.Color; \/\/ aColor is Red\r\n  var bColor = b.FrontLight.Color; \/\/ bColor is Red\r\n\r\n  a.FrontLight.Color = Color.Blue;\r\n  var bColor2 = b.FrontLight.Color; \/\/ bColor2 is Red\r\n\r\n  var aColor2 = a.FrontLight.Color; \/\/ aColor2 is Red (!)\r\n\r\n  if (a.FrontLight != a.FrontLight) TheWorldHasGoneMad(); \/\/ executes!\r\n}\r\n<\/pre>\n<p>This time, we have the callback create a brand new red <code>Light<\/code>. When we evaluate <code>a<\/code><code>.FrontLight<\/code><code>.Color<\/code>, the first thing that XAML needs to do is obtain the value of <code>a<\/code><code>.FrontLight<\/code>, and since nobody has set a value, XAML asks the callback to produce the default. The callback creates a fresh red <code>Light<\/code> and returns it, and that brand new light is the value of the <code>a<\/code><code>.FrontLight<\/code> property. The <code>Example<\/code> function reads the color and gets <code>Red<\/code>.<\/p>\n<p>The same thing happens when you read the color from <code>b<\/code><code>.FrontLight<\/code><code>.Color<\/code>.<\/p>\n<p>So far so good. The <code>a<\/code> and <code>b<\/code> objects each have separate <code>FrontLight<\/code> lights.<\/p>\n<p>Okay, now things get interesting: When we try to change the color of <code>a<\/code>&#8216;s <code>Front\u00adLight<\/code> to <code>Blue<\/code>, the assignment succeeds, and it doesn&#8217;t affect the color of <code>b<\/code>&#8216;s <code>Front\u00adLight<\/code>, but when we try to read the color of <code>a<\/code>&#8216;s <code>Front\u00adLight<\/code>, we get <code>Red<\/code> again. What happened?<\/p>\n<p>In the assignment <code>a<\/code><code>.FrontLight<\/code><code>.Color = Color<\/code><code>.Blue<\/code>, the first thing that happens is the fetch of the <code>FrontLight<\/code> property of the <code>a<\/code> object. And since we <i>still<\/i> haven&#8217;t set a value for the <code>FrontLight<\/code> property, XAML uses the default value. And XAML does that by calling the callback, and the callback creates a brand new <code>Light<\/code>. Until a value for the <code>FrontLight<\/code> property is set, <i>every attempt to read the <code>FrontLight<\/code> property will produce a new red <code>Light<\/code><\/i>. In other words, the default value is not cached. XAML calls the callback each time it needs the default value.<\/p>\n<p>The code sets the color of this brand new light to <code>Blue<\/code>. But that brand new light isn&#8217;t being saved anywhere. It doesn&#8217;t become the value of the <code>FrontLight<\/code> property. It ends up orphaned, waiting for the next GC to clean it up.<\/p>\n<p>Later, you read <code>a<\/code><code>.FrontLight<\/code><code>.Color<\/code>. Again, the first step is to retrieve the <code>FrontLight<\/code> property from <code>a<\/code>, and since no value has been set yet, XAML asks the callback to produce the default value, and the callback creates a brand new red <code>Light<\/code>. Every fetch of the <code>FrontLight<\/code> property produces a brand new red <code>Light<\/code>.<\/p>\n<p>This also explains why the final statement reports that the world has gone mad: The two reads of the <code>FrontLight<\/code> property each produced a different red <code>Light<\/code>.<\/p>\n<p>Producing a brand new object in response to the default value callback is a bad idea.<\/p>\n<p>The intended purpose of the callback is to let you have a default value that is itself a dependency object. Since dependency objects have thread affinity, you cannot use the same object for all callers, because the callers may come from different threads. The callback lets you look in some per-thread storage to obtain the correct object for that thread. In the worst case, you can have your own private cache of objects indexed by thread.\u00b9<\/p>\n<p>Okay, but what if the dependency property&#8217;s type is a mutable type. One solution is to make <code>null<\/code> the default value of the property. As immutable things go, <code>null<\/code> looks quite immutable. Everybody who wants to change the <code>FrontLight<\/code> color must first provide a <code>FrontLight<\/code>. But what if you want the default value to be non-null? We&#8217;ll look at this <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20191003-00\/?p=102959\"> next time<\/a>.<\/p>\n<p>\u00b9 <a href=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20060502-07\/?p=31333\"> A cache with a bad policy is another name for a memory leak<\/a>. One way to avoid this problem is to put weak references in the cache, so that the objects remain alive only as long as somebody is observing them. Scavenge dead slots in the dictionary periodically to clean out the tombstones. For example, you might scavenge after a certain number of objects have been added to the cache.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Spooky action at a distance.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-102950","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Spooky action at a distance.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/102950","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=102950"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/102950\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=102950"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=102950"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=102950"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}