How to get default compile-time value of Auto-Implemented property C# 6.0 after it changed?

  1. For instance property, just new an instance then get the default property value is the easiest way.
  2. For static property, the default value can be preserved in the static constructor.
    public static class MyClass
    {
        public static int MyProp1 { get; set; } = 100;
        public static bool MyProp2 { get; set; } = false;

        private static Dictionary<string, object> defaultValues;

        static MyClass()
        {
            defaultValues = new Dictionary<string, object>();

            foreach(var prop in typeof(MyClass).GetProperties(BindingFlags.Static| BindingFlags.Public | BindingFlags.NonPublic))
            {
                defaultValues[prop.Name] = prop.GetValue(null);
            }
        }

        public static (T,bool) GetDefault<T>(string propName)
        {
            if(defaultValues.TryGetValue(propName, out object value))
            {
                return ((T)(value), true);
            }
            return (default, false);
        }
    }

    //test codes
    static void Main(string[] args)
    {

        MyClass.MyProp1 = 1000;
        MyClass.MyProp2 = true;

        var defaultValueOrProp1 = MyClass.GetDefault<int>("MyProp1");
        if(defaultValueOrProp1.Item2)
        {
            Console.WriteLine(defaultValueOrProp1.Item1);//100
        }

        var defaultValueOrProp2 = MyClass.GetDefault<bool>("MyProp2");
        if (defaultValueOrProp2.Item2)
        {
            Console.WriteLine(defaultValueOrProp2.Item1);//false
        }
    }



Following Line added by question author:

For setting property with default value

private static void ResetPropertyValue(string PropertyName)
{ 
    typeof(Options).GetProperty(PropertyName).SetValue(null, 
    defaultValues[PropertyName]);
}

Properties are little more then Syntax sugar for get/set function pairs. And what you got there is little more then a basic, bog-standart assignment/function call around when the constructor runs. As all literals and constatns, it should no longer exist at runtime.

The naive way would be to have a constant like IsSoundEffectsDefaultValue. And I do think that is sufficient in most cases.

There is a off-chance that a old idea of mine might apply to your broader problem. I need to search for the code however.

Edit:

I could not find my old code, unfortunately. I can re-create it however. The basic idea is to have multiple "layers" of values, with one value hiding (but not overwriting) the other.

public class defaultAble<T>{
    readonly T defaultValue;

    //constructor
    public defaultAble(T defaultValue){
        this.defaultValue = defaultValue;
        //First set the value
        RestoreDefault();
    }

    public RestoreDefault(){
        value = this.defaultValue;
    }

    public T value { get; set; }
}

Edit 2:

There might be a even better solution in WPF/MVVM circles. A lot of MVVM is writing properties with the same code - one that raises change notification by INotifyPropertyChanged. And a big issue with Properties is not writing the backing field by accident.

Some people figured out solutions like putting the actuall value and all the code into a something like a Dictionar<string, object> mostly automagically. I am not sure about the details, however. Also DependancyProperties might get close to it too.


One approach you could use would be based on Custom Attributes. You could define as Custom Attribute to hold the default value. For example,

public class DefaultValueAttribute:Attribute
{
    public object DefaultValue{get;set;}
    public DefaultValueAttribute(object defaultValue)=>DefaultValue = defaultValue;
}

You can now use the Attribute to store the default value as

public static class SomeClass
{
  [DefaultValueAttribute(true)]
  public static bool IsSoundEffects { get; set; } = true;
}

For retrieving the same, you could depend on reflection.

var defaultValue = typeof(SomeClass).GetProperty(nameof(SomeClass.IsSoundEffects), BindingFlags.Public | BindingFlags.Static)
                                .GetCustomAttribute<DefaultValueAttribute>().DefaultValue;

Making the reflection call a generic method to be used with other properties.

public T GetDefaultValue<T>(string propertyName)
{
    var result = typeof(SomeClass).GetProperty(nameof(SomeClass.IsSoundEffects), BindingFlags.Public | BindingFlags.Static)
                                .GetCustomAttribute<DefaultValueAttribute>().DefaultValue;

    return (T)Convert.ChangeType(result,typeof(T));
}

Usage

var defaultValue = GetDefaultValue<bool>(nameof(SomeClass.IsSoundEffects));