Click here to Skip to main content
15,867,453 members
Articles / Programming Languages / C#
Tip/Trick

C# Automatic Property Default Value Extension Methods

Rate me:
Please Sign up or sign in to vote.
4.85/5 (6 votes)
21 Aug 2011CPOL2 min read 53.1K   15   3
This article shows how to automatically initialize/reset automatic properties' default values.

Automatic properties are great but the annoyance of not being able to set them automatically deters a lot of people from using them.
What we (read - I) want to be able to do is something like this:


C#
double MyPie { get; set; } = "3.141";
string MyLove { get; set; } = "Pizza";

The default value attribute in System.ComponentModel is of no help there, though a lot of us (read - me) tried that in the beginning:


C#
[DefaultValue(0.3141)]
double MyPie { get; set; }

[DefaultValue("Pizza")]
string MyLove { get; set; }

Initializing the properties one by one in the constructor is at least as annoying as simply doing this:


C#
double _myPie = 0.3141;
double MyPie { get { return _myPie; } set { _myPie = value; } }

double _myLove = "Pizza";
double MyLove { get { return _myLove; } set { _myLove = value; } }

Luckily, the nice little feature of extension methods allows us something not exactly optimal or fully elegant - but functional and a good exercise in C# clockwork.
So with just a bit of hammering, we can enable automatic reset properties to their declared System.ComponentModel.DefaultValueAttribute if any was specified.
Here is some test code:


C#
using System;
using System.ComponentModel;
using System.Text;
using System.Windows.Forms;

using CSharpUtils;
namespace MyAppNamespace
{
  public class TestClass
  {
    [DefaultValue(0.3141)]
    public double MyPie { get; set; }

    [DefaultValue("Pizza")]
    public string MyLove { get; set; }

    public TestClass()
    {
      MessageBox.Show(string.Format("MyPie = {0}, MyLove = {1}", 
                      MyPie, MyLove == null ? "null" : MyLove));
      int ret = (this as Object).ResetPropsUsingDefaultAttributes(false);
      MessageBox.Show(string.Format(
                      "MyPie = {0}, MyLove = {1}. {2} properties we set", 
                      MyPie, MyLove == null ? "null" : MyLove, ret));
      MyLove = "My dear wife";
      MessageBox.Show(string.Format("MyPie = {0}, MyLove = {1}", 
                      MyPie, MyLove == null ? "null" : MyLove));
      ret = (this as Object).ResetPropsUsingDefaultAttributes(false);
      MessageBox.Show(string.Format(
                      "MyPie = {0}, MyLove = {1}. {2} properties we set", 
                      MyPie, MyLove == null ? "null" : MyLove, ret));
    }
  }
}

This (as you may have already guessed) is done using an extension method to the System.Object class.
You will need a public static class to define the extension method in. Here's the basic implementation source:


C#
using System;
using System.Text;
using System.Reflection;
using System.ComponentModel;

namespace CSharpUtils
{
  static class CSharpUtilsExtensionMethods
  {
    public static int ResetPropsUsingDefaultAttributes(
           this Object oThis, bool initInheritedProperties)
    {
      int count = 0;
      //BindingFlags.Static
      Type oType = oThis.GetType();
      PropertyInfo[] infos = oType.GetProperties(BindingFlags.NonPublic | 
                     BindingFlags.Public | BindingFlags.Instance);
      foreach (PropertyInfo inf in infos)
      {
        if (initInheritedProperties || inf.DeclaringType.Equals(oType))
        {
          object[] oDefAtts = inf.GetCustomAttributes(
            typeof(DefaultValueAttribute), initInheritedProperties);
          if (oDefAtts.Length > 0)
          {
            DefaultValueAttribute defAtt = 
                 oDefAtts[oDefAtts.Length - 1] as DefaultValueAttribute;
            if (defAtt != null && defAtt.Value != null && 
                !defAtt.Value.Equals(inf.GetValue(oThis, 
                 BindingFlags.GetProperty, null, null, null)))
            {
              inf.SetValue(oThis, defAtt.Value, BindingFlags.SetProperty, 
                           null, null, null);
              count++;
            }
          }
        }
      }
      return count;
    }
  }
}

All that's left now is using our test class (here again - with no message box and other nonsense).


C#
using System;
using System.ComponentModel;
using System.Text;
using System.Windows.Forms;

using CSharpUtils;
namespace MyAppNamespace
{
  public class TestClass
  {
    [DefaultValue(0.3141)]
    public double MyPie { get; set; }

    [DefaultValue("Pizza")]
    public string MyLove { get; set; }


    public void ResetProps()
    {
      (this as Object).ResetPropsUsingDefaultAttributes(false);
    }
    public TestClass()
    {
      ResetProps();
    }
  }
}

Notes:



  • To use the extension method, the .cs file making the call must have a 'using' declaration of the namespace where the extension method resides in.
  • Passing true for the parameter initInheritedProperties also initializes any parent class properties - at the expense of possibly resetting already initialized properties. You can always extend the extension method to try and account for these cases.
  • Resetting the properties in this manner also works outside the constructor - anywhere in the program with proper access.
  • There's still the annoyance of having to add a line in the constructor - but it is just one line and will not require additional modifications if properties are added, removed, or their type/default value is changed.

There you go, have fun.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Israel Israel
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Generalnice, but personally i dont like adding performance overhead... Pin
GParkings2-Sep-11 12:48
GParkings2-Sep-11 12:48 
GeneralReason for my vote of 4 Interesting, but too slow. Slow meth... Pin
Kelqualyn22-Aug-11 22:34
Kelqualyn22-Aug-11 22:34 
SuggestionMinor suggestion... Pin
Andrew Rissing22-Aug-11 4:21
Andrew Rissing22-Aug-11 4:21 
You don't need to perform the following to use the extension:

C#
(this as Object).ResetPropsUsingDefaultAttributes(false);


You can just do the following:

C#
this.ResetPropsUsingDefaultAttributes(false);

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.