我有以下 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;
}
}
下面是 IncognitoString
和 IncognitoStringConverter
的实现:
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/