How does the WPF dependency property design save memory consumption?

First, suppose you create a class with a dozen properties. Create 100,000 of them. How many object references do you now have? 1,200,000.

Now implement a class called DependencyObject:

public class DependencyObject
{
    public DependencyObject()
    {
       LocalValues = new Dictionary<string, object>();
    }

    protected Dictionary<string, object> LocalValues { get; set; }

    public DependencyObject Parent { get; set; }

    protected object GetValue(string propertyName)
    {
       if (LocalValues.ContainsKey(propertyName))
       {
          return LocalValues[propertyName];
       }
       return Parent.GetValue(propertyName);
    }

    protected void SetValue(string propertyName, object value)
    {
       LocalValues[propertyName] = value;
    }
}

Build a derived class like this:

public class MyDependencyObject : DependencyObject
{
    public SomeType Property1
    {
       get { return (SomeType)GetValue("Property1"); }
       set { SetValue("Property1", value]; }
    }

    // create 11 more properties like this
}

Now create 100,000 instances of MyDependencyObject and set their Parent. How many object references are used (not counting the parent)? 300,000.

That's how property value inheritance works in dependency objects.


See the following link: Dependency Properties.

What is declared by an object as a dependency property is in fact nothing more than an identifier. This static "property" is really a key which associates an object with a specific storage identifier. For example graphical objects have a Background property that can be set explicitly or through the use of templates or styles..

As long as a Dependency Property uses its default state (which is very common), it won't take up any additional memory since the default value will be used. The default value isn't stored per instance, it is stored per Dependency Property and it's set by metadata.

Example, notice how Brushes.Black is set as the default value

public static readonly DependencyProperty ForegroundProperty =
    DependencyProperty.Register(
        "Foreground",
        typeof(Brush),
        typeof(TextElement),
        new FrameworkPropertyMetadata(Brushes.Black, ...));

Think of it this way: Say you have four TextBlocks in Xaml

<StackPanel>
    <TextBlock .../>
    <TextBlock .../>
    <TextBlock .../>
    <TextBlock Foreground="Green" .../>
</StackPanel>

The three TextBlocks at the top have Foreground set to Black although you have never explicitly set it to Black. They are using their default value. So for the Foreground property for the three TextBlocks above, you only need one field (since it is a static field).

For the forth TextBlock though, you have explicitly set Foreground to Green, so that value is inserted into a dictionary as the local value for Foreground on this instance and thus requires additional memory (also, it will end up at place number 3 in the list below, overriding Setters, Triggers etc).

Also, see the following post by Josh Smith, it's a good read: Demystifying dependency properties

There is a well-defined set of rules which is used internally by WPF to figure out what the real value of a DP is. Here is a brief summary of the rules of precedence used when resolving the value of a DP (read more about it here):

  1. Property system coercion
  2. Active animations, or animations with a Hold behavior
  3. Local value
  4. TemplatedParent template
  5. Style triggers
  6. Template triggers
  7. Style setters
  8. Theme style
  9. Inheritance
  10. Default value from dependency property metadata

Edit: To answer the comment from Duane

If you explicitly set the value to the same value as the default value, it will still get stored as the local value. This can easily be verified with the following Xaml.

Both TextBlocks will have Foreground set to Black, but the later has a local value set. The Style will only be able to set Foreground on the first TextBlock and not the later since Style setters has lower priority than local value.

<StackPanel>
    <StackPanel.Resources>
        <Style TargetType="TextBlock">
            <Setter Property="Foreground" Value="Green"/>
        </Style>
    </StackPanel.Resources>
    <TextBlock Text="Displays in Green"/>
    <TextBlock Foreground="Black" Text="Displays in Black"/>
</StackPanel>