c# - 具有空默认值的配置字符串

标签 c# .net string configuration app-config

我有以下 ConfigurationProperty 作为元素的一部分:

[ConfigurationProperty("example", IsRequired = false, DefaultValue = null)]
public string Example { 
    get { return (string)base["example"]; }
    set { base["example"] = value; }
}

如果我按如下方式设置它,它会接受 "Hello" 字符串并正常工作:

<myElement example="Hello"/>

如果它不存在,我就会遇到问题:

<myElement/>

它不是采用上面指定的默认值 null,而是采用 String.Empty。为什么会这样,我怎样才能让它采用默认值 null

更新

肯定是因为 base["example"] 返回 String.Empty,其中 base 是一个 ConfigurationElement (索引器在此处定义:https://msdn.microsoft.com/en-us/library/c8693ks1(v=vs.110).aspx),但我仍然不确定为什么它不采用 null 的值。

更新

甚至 DefaultValue = default(string) 也将字符串设置为 String.Empty

更新

如果属性在配置中不存在,即使 base.Properties.Contains("example") 也会返回 true

最佳答案

Reference Source for the ConfigurationProperty class来看,这可能不是错误,而是功能。

这里是相关的内部方法,InitDefaultValueFromTypeInfo(我做了一些小的格式修改):

private void InitDefaultValueFromTypeInfo(ConfigurationPropertyAttribute attribProperty,
                                          DefaultValueAttribute attribStdDefault) {
     object defaultValue = attribProperty.DefaultValue;

     // If there is no default value there - try the other attribute ( the clr standard one )
     if ((defaultValue == null || defaultValue == ConfigurationElement.s_nullPropertyValue) &&
         (attribStdDefault != null)) {
         defaultValue = attribStdDefault.Value;
     }

     // If there was a default value in the prop attribute - check if we need to convert it from string
     if ((defaultValue != null) && (defaultValue is string) && (_type != typeof(string))) {
         // Use the converter to parse this property default value
         try {
             defaultValue = Converter.ConvertFromInvariantString((string)defaultValue);
         }
         catch (Exception ex) {
             throw new ConfigurationErrorsException(SR.GetString(SR.Default_value_conversion_error_from_string, _name, ex.Message));
         }
     }

     if (defaultValue == null || defaultValue == ConfigurationElement.s_nullPropertyValue) {
         if (_type == typeof(string)) {
             defaultValue = String.Empty;
         }
         else if (_type.IsValueType) {
             defaultValue = TypeUtil.CreateInstanceWithReflectionPermission(_type);
         }
     }

     SetDefaultValue(defaultValue);
 }

最后一个 if block 很有趣:如果您的属性的类型为 string,并且默认值为 null,则默认值为更改为 string.Empty

第一个 if block 暗示了对这种特殊行为的可能解释。 [ConfigurationProperty] 属性的 DefaultValue 属性是可选的。如果 DefaultValue 不是由程序员设置的,那么它默认为 null 本身。第一个 if block 使用默认的 null 来检查是否指定了 DefaultValue。如果没有,它会回退到从 [DefaultValue] 属性中获取默认值(如果存在的话)。

这一切意味着:指定 DefaultValue = null 与根本不指定它具有相同的效果,在这种情况下,配置子系统为字符串选择一个“合理的”默认值:空字符串。

解决方法:

这里有一个有点古怪的解决方法:不要将您的配置属性声明为 string,而是作为围绕字符串的薄包装类型;然后声明一个合适的类型转换器:

[ConfigurationProperty("name", IsRequired = false)]
[TypeConverter(typeof(IncognitoStringConverter))]  // note: additional attribute!
public IncognitoString Name                        // note: different property type
{
    get
    {
        return (IncognitoString)base["name"];
    }
    set
    {
        base["name"] = value;
    }
}

下面是 IncognitoStringIncognitoStringConverter 的实现:

public struct IncognitoString
{
    private IncognitoString(string value)
    {
        this.value = value;
    }

    private readonly string value;

    public static implicit operator IncognitoString(string value)
    {
        return new IncognitoString(value);
    }

    public static implicit operator string(IncognitoString incognitoString)
    {
        return incognitoString.value;
    }

    … // perhaps override ToString, GetHashCode, and Equals as well.
}

public sealed class IncognitoStringConverter : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        return (IncognitoString)(string)value;
    }
}

因为 IncognitoString 可以隐式转换为 string,所以您可以将属性值分配给任何字符串变量。我知道,获取可为 null 的属性很复杂,而且非常复杂。也许只是接受空字符串。

关于c# - 具有空默认值的配置字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29799341/

相关文章:

c# - 为什么没有 Convert.toFloat() 方法?

.net - .NET 中是否有类似 perl 的 Regexp::Grammars 或标记的子模式?

C# - 以编程方式创建 SQL Server 表

c++ - 如何从cpp中的给定字符串中提取特定字符串?

C#,有没有 "thread-safe"流这样的东西?

c# - Devexpress时间编辑控制: How to get selected portion of Hour or Minute in the control?

c# - Apache 点燃 2.1 : Getting a "Conflicting type IDs" error after upgrading from 2. 0

c# - 使 Javascript 代码在 Page Start 上运行

c - 为什么字符串连接可能会在每个连接前加上垃圾前缀?

java - Android:当两个字符串相等时,在 onPostExecute() 中启动一个新的 Activity