简体   繁体   English

更改后如何获取自动实现属性 C# 6.0 的默认编译时值?

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

Shortly, The new C# 6.0 Auto-Implemented Property allows us to make this不久,新的 C# 6.0 自动实现的属性使我们能够做到这一点

    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.现在在某个地方,我更改了属性IsSoundEffects = 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 // 真正的编译时 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] xiangbin.pang对反射方式的回答[Short-One]

Christopher answers for constants as default values. Christopher将常量作为默认值回答。

  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.对于 static 属性,可以在 static 构造函数中保留默认值。
    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.属性只是获取/设置 function 对的语法糖。 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 .天真的方法是有一个像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:编辑2:

There might be a even better solution in WPF/MVVM circles. WPF/MVVM 圈子中可能有更好的解决方案。 A lot of MVVM is writing properties with the same code - one that raises change notification by INotifyPropertyChanged.许多 MVVM 正在使用相同的代码编写属性 - 一个通过 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.有些人想出了解决方案,例如将实际值和所有代码自动放入Dictionar<string, object>之类的东西中。 I am not sure about the details, however.但是,我不确定细节。 Also DependancyProperties might get close to it too. DependancyProperties 也可能接近它。

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您现在可以使用 Attribute 将默认值存储为

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. OP :我从数据库中填充属性。 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选项 1 - 使用 System.ComponentModel.DefaultValue

On of the standard solutions for setting default value for properties, is using DefaultValue attribute of the .NET Framework.设置属性默认值的标准解决方案之一是使用 .NET 框架的DefaultValue属性。 You can see this pattern in a lot of classes in .NET Framework. 您可以在 .NET 框架的很多类中看到这种模式。 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:然后 .NET 框架通过PropertyDescriptor.ResetValue方法为您提供重置功能:

System.ComponentModel.TypeDescriptor.GetProperties(this)["MyProperty"].ResetValue(this);

Option 2 - Create a static Default instance选项 2 - 创建 static 默认实例

You can have a static default instance of the class and use it for resetting properties.您可以拥有 class 的默认实例 static 并将其用于重置属性。

If you want to have the default instance as private you can keep it as a single instance field.如果您想将默认实例设为private ,您可以将其保留为单个实例字段。

If you want the default instance as public you need to create a property and return a new instance in the getter.如果您希望将默认实例设为public ,您需要创建一个属性并在 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 .使用PropertyInfo.GetConstantValue 方法

Consider your class考虑您的 class

class YourClass
{
    public static bool IsSoundEffects { get; set; } = true;   // C# 6.0 allows this
}

and consider a "getter" class you create并考虑您创建的“吸气剂” class

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您可以使用以下方法

  1. using constants which is good if no need to change variables after initializations.如果在初始化后不需要更改变量,使用常量是很好的。
  2. use static readonly if only variable can changed in cosntructor.如果只有变量可以在 cosntructor 中更改,则只读使用 static。
  3. use dictionary with使用字典

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM