Shortly, The new C# 6.0 Auto-Implemented Property allows us to make this
public static bool IsSoundEffects { get; set; } = true; // C# 6.0 allows this
Now in somewhere, I changed the property IsSoundEffects = false
, So accessing it will be false.
hmm, So how to get the actual real default compile-time auto-implemented property value.
Something Like:
Type.GetPropertyDefaultValue(IsSoundEffects);
// A real compile-time one = true
OR
default(IsSoundEffects) // idk, something like that
Why I need that?
because I filling the properties from the database. and restore it if user need to restore the default values. for example settings.
Looks strange? I searched enough but all examples about the auto-implemented feature did not restore the default value.
Edited
The best approaches provided by
xiangbin.pang answer for reflection way [Short-One]
Christopher answers for constants as default values.
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));
OP : I filling the properties from the database. and restore it if user need to restore the default values.
This post tries to answer based on based on above requirement which you mentioned in the question.(Not based on the question title.)
Option 1 - Using System.ComponentModel.DefaultValue
On of the standard solutions for setting default value for properties, is using DefaultValue
attribute of the .NET Framework. You can see this pattern in a lot of classes in .NET Framework. For example:
[System.ComponentModel.DefaultValue(true)]
public static bool MyProperty{ get; set; } = true;
Then .NET Framework gives you the reset functionality by PropertyDescriptor.ResetValue
method:
System.ComponentModel.TypeDescriptor.GetProperties(this)["MyProperty"].ResetValue(this);
Option 2 - Create a static Default instance
You can have a static default instance of the class and use it for resetting properties.
If you want to have the default instance as private
you can keep it as a single instance field.
If you want the default instance as public
you need to create a property and return a new instance in the getter.
public class MyClass
{
private static readonly MyClass Default = new MyClass();
//OR
//public static MyClass Default { get { return new MyClass(); } }
public bool MyProperty{ get; set; } = true;
public void Reset()
{
this.MyProperty = Default.MyProperty;
}
}
Use PropertyInfo.GetConstantValue Method .
Consider your class
class YourClass
{
public static bool IsSoundEffects { get; set; } = true; // C# 6.0 allows this
}
and consider a "getter" class you create
class DefaultGetter
{
T GetDefault<TClass, TProp>(string propertyName) where T : new()
{
if (!defaults.TryGetValue(typeof(T), out var defaultValues)
if (!defaultValues.TryGetValue(propertyName, out var value))
{
// reflect on prototype getting all the PropertyInfo
// and store them in the dictionary of dictionaries
// then assign to value...
defaults[typeof(TClass)] = defaultValues = typeof(TClass).GetProperties().Select(x => new { x.Name, Value = x.GetConstantValue() }).ToDictionary(x => x.Name);
}
value = defaultValues[propertyName]
}
return (TProp)value;
}
IDictionary<Type, IDictionary<string, object> defaults = new ... // elided for brevity
}
You would use it like this:
var defaultIsSoundEffects = defaultGetter.GetDefault<YourClass, bool>("IsSoundEffects");
You can use following approaches
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.