Click here to Skip to main content
Licence CPOL
First Posted 14 May 2008
Views 32,965
Downloads 43
Bookmarked 21 times

Setting Default Values on Automatic Properties

By Steven Berkovitz | 14 May 2008
An article on implementing default values on Automatic Properties
1 vote, 12.5%
1

2
2 votes, 25.0%
3
3 votes, 37.5%
4
2 votes, 25.0%
5
3.53/5 - 8 votes
μ 3.53, σa 2.28 [?]

Introduction

C# 3.0 introduces a great new feature called Automatic Properties, and if you haven’t already read about them, I would encourage you to read Scott Guthrie's introductory post.

As great as they are and as much time as they save, Automatic Properties have a serious drawback – you can’t set the default value of the property. Instead, the compiler will initialize value properties to 0, reference properties to null, and enum’s to the first member, and while this might work for some applications, it wasn’t working for mine.

Background

When I thought about the implementation, two options became apparent. One, I could create a base object class and have all of my classes inherit from this base class. This however isn’t a great solution because a number of my classes inherit from other classes outside of my control, and since .NET does not support multiple inheritances, it was clear this wasn’t going to work. To my rescue was the also new C# 3.0 feature, Extension Methods. If you haven’t already heard about Extension Methods, I’d recommend reading another one of Scott Guthrie's blog posts about them.

Using the Code

Using the code requires that you decorate your properties with an attribute already available in the System.ComponentModel namespace – if you haven’t already guessed it, it’s the aptly named DefaultValueAttribute attribute. As well, it requires a quick call to the InitDefaults() extension method from the constructor which I will discuss a bit later.

The attached code supplies a demo implementation of the TestObject and TestObjectInherited classes:

public class TestObject
    {
        public TestObject()
        {
            this.InitDefaults();
        }

        [DefaultValue(-45)]
        public int DefaultInt
        {
            get;
            set;
        }

        [DefaultValue(10.23)]
        public double DefaultDouble
        {
            get;
            set;
        }

        [DefaultValue(true)]
        public bool DefaultBool
        {
            get;
            set;
        }

        [DefaultValue(TestEnum.Value2)]
        public TestEnum DefaultEnum
        {
            get;
            set;
        }

        [DefaultValue("DefaultString!")]
        public string DefaultString
        {
            get;
            set;
        }

        public string StringWithoutDefault
        {
            get;
            set;
        }

        public string ValueOfPrivateProperty
        {
            get
            {
                return PrivateProperty;
            }
        }

        [DefaultValue("This is a private property!")]
        protected string PrivateProperty
        {
            get;
            set;        
        }
    }

The magical InitDefaults() method is implemented as an extension method which uses reflection to set the value of the properties to the default value:

public static void InitDefaults(this object o)
        {
            PropertyInfo[] props = o.GetType().GetProperties(BindingFlags.Public | 
                BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);

            for (int i = 0; i < props.Length; i++)
            {
                PropertyInfo prop = props[i];                

                if (prop.GetCustomAttributes(true).Length > 0)
                {
                    object[] defaultValueAttribute = 
                        prop.GetCustomAttributes(typeof(DefaultValueAttribute), true);

                    if (defaultValueAttribute != null)                    
                    {
                        DefaultValueAttribute dva = 
                            defaultValueAttribute[0] as DefaultValueAttribute;
                        
                        if(dva != null)
                            prop.SetValue(o, dva.Value, null);                                
                    }
                }
            }
        }

Points of Interest

I decided to support initializing the default value of properties in inherited classes, but if you don’t want this behavior, you can simply pass false to GetCustomAttributes().

if (prop.GetCustomAttributes(false).Length > 0)
                {
                    object[] defaultValueAttribute = prop.GetCustomAttributes
                        (typeof(DefaultValueAttribute), false);

                    if (defaultValueAttribute != null)                    
                    {
                        DefaultValueAttribute dva = 
                            defaultValueAttribute[0] as DefaultValueAttribute;
                        
                        if(dva != null)
                            prop.SetValue(o, dva.Value, null);                                
                    }
                }

History

  • 14th May, 2008: Initial post

License

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

About the Author

Steven Berkovitz

Web Developer

Canada Canada

Member
Steven is VP Development at MBC Computer Solutions Ltd. (http://www.mbccs.com), a Richmond Hill based company specializing in e-Business Application Development, e-Store Solutions, Managed Co-Location and Proactive IT services.
 
Steven has over 10 years experience in software and hardware design and is experienced with a large array of platforms, technologies and languages.
 
In his spare time, Steven enjoys a wide array of music, is an avid skier and enjoys spending time with friends.
 
Steven is the primary contributor of MBC's blog which can be read at http://blogs.mbccs.com/mbccomputersolutions

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
Questionover-design? Pinmemberffffffffffffffffffff10:03 29 Oct '08  
GeneralDiffent approach PinmemberGünther M. FOIDL1:01 8 Oct '08  
RantVote for initialization to be added as a language feature. PinmemberLaughing.John14:08 23 Aug '08  
GeneralI don't think its a good idea PinmemberJorge Bay Gondra4:18 22 Aug '08  
GeneralAnother option PinmemberAjek12:02 20 May '08  
GeneralRe: Another option Pinmembernsimeonov17:32 9 Jun '09  
GeneralA opinion PinmemberRicky Wang20:57 19 May '08  
GeneralI'd do it differently... PinmemberPIEBALDconsult14:49 14 May '08  
I'd do it differently... but no one here should be surprised about that. Big Grin | :-D
 
I'd eliminate some of the local variables by using foreach rather than for.
 
I'd eliminate the extra check for attributes.
 
I might also add type checking to be sure the property can be set to the value.
 
Also, if you instantiate a large number of a particular type and then perform InitDefaults on each, you'll hit Reflection a number of times, at considerable cost, always getting the same results, so I suggest caching the results to improve performance.
 

public static void InitDefaults ( this object o )
{
    foreach 
    (
        System.Reflection.PropertyInfo prop 
    in 
        o.GetType().GetProperties
        (
            System.Reflection.BindingFlags.Public 
        | 
            System.Reflection.BindingFlags.NonPublic 
        | 
            System.Reflection.BindingFlags.Instance 
        | 
            System.Reflection.BindingFlags.Static
        )
    )
    {
        foreach 
        ( 
            System.ComponentModel.DefaultValueAttribute dva
        in
            prop.GetCustomAttributes 
            ( 
                typeof(System.ComponentModel.DefaultValueAttribute) 
            , 
                true 
            )
        )
        {
            if ( o.GetType().IsAssignableFrom ( dva.Value.GetType() ) )
            {
                prop.SetValue ( o , dva.Value , null ) ;
            }
        }
    }
}
 
(Well, that compiles, but I'm not sure the type check will work, I haven't tested it.)
GeneralRe: I'd do it differently... PinmemberSeishin#2:56 15 May '08  
GeneralRe: I'd do it differently... PinmemberPIEBALDconsult6:56 15 May '08  
GeneralRe: I'd do it differently... PinmemberPIEBALDconsult8:39 15 May '08  
GeneralRe: I'd do it differently... PinmemberSeishin#9:30 15 May '08  
GeneralRe: I'd do it differently... PinmemberPIEBALDconsult10:45 15 May '08  
GeneralRe: I'd do it differently... PinmemberSeishin#10:47 15 May '08  
GeneralRe: I'd do it differently... PinmemberPIEBALDconsult11:15 15 May '08  
GeneralI Don't See The Value In Automatic Properties PinmvpJohn Simmons / outlaw programmer12:26 14 May '08  
GeneralRe: I Don't See The Value In Automatic Properties [modified] PinmemberPIEBALDconsult14:16 14 May '08  
GeneralRe: I Don't See The Value In Automatic Properties PinmemberWilliam E. Kempf7:47 15 May '08  
GeneralRe: I Don't See The Value In Automatic Properties PinmemberPIEBALDconsult8:53 15 May '08  
GeneralRe: I Don't See The Value In Automatic Properties PinmemberWilliam E. Kempf9:37 15 May '08  
GeneralRe: I Don't See The Value In Automatic Properties PinmemberPIEBALDconsult10:29 15 May '08  
GeneralRe: I Don't See The Value In Automatic Properties PinmemberWilliam E. Kempf10:42 15 May '08  
GeneralRe: I Don't See The Value In Automatic Properties PinmemberSteven Berkovitz10:44 15 May '08  
GeneralRe: I Don't See The Value In Automatic Properties PinmemberWilliam E. Kempf10:46 15 May '08  
GeneralRe: I Don't See The Value In Automatic Properties PinmemberPIEBALDconsult10:49 15 May '08  

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

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

Permalink | Advertise | Privacy | Mobile
Web01 | 2.5.120210.1 | Last Updated 14 May 2008
Article Copyright 2008 by Steven Berkovitz
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid