具有Null DefaultValue的配置字符串

Ale*_*dru 15 .net c# string configuration app-config

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

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

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

<myElement example="Hello"/>
Run Code Online (Sandbox Code Playgroud)

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

<myElement/>
Run Code Online (Sandbox Code Playgroud)

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.

sta*_*ica 10

参考源ConfigurationProperty来看,这可能不是一个错误,而是一个功能.

这是相关的内部方法,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);
 }
Run Code Online (Sandbox Code Playgroud)

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

第一个if块暗示了这种奇特行为的可能解释.该[ConfigurationProperty]属性的DefaultValue属性是可选的.如果DefaultValue程序员没有设置,则默认为null自己.第一个if块使用该默认值null来检查是否DefaultValue指定了a .如果没有,它将回退到从[DefaultValue]属性中获取默认值(如果存在这样的属性).

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

解决方法:

这是一个有点hacky的解决方法:不要将配置属性声明为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;
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是为实现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;
    }
}
Run Code Online (Sandbox Code Playgroud)

因为IncognitoString可以隐式转换为string,所以可以将属性值赋给任何字符串变量.我知道,它只是为了获得可以为空的属性而且非常复杂.也许只是忍受空字符串.

  • 我见过大约2014年至2015年的任何问题的最佳答案!:d (2认同)