2014-08-13 10:39:27 +01:00
//
// System.Configuration.ConfigurationElement.cs
//
// Authors:
// Duncan Mak (duncan@ximian.com)
// Lluis Sanchez Gual (lluis@novell.com)
// Martin Baulig <martin.baulig@xamarin.com>
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
// Copyright (c) 2012 Xamarin Inc. (http://www.xamarin.com)
//
using System.Collections ;
using System.Xml ;
using System.Reflection ;
using System.IO ;
using System.ComponentModel ;
namespace System.Configuration
{
public abstract class ConfigurationElement
{
string rawXml ;
bool modified ;
ElementMap map ;
ConfigurationPropertyCollection keyProps ;
ConfigurationElementCollection defaultCollection ;
bool readOnly ;
ElementInformation elementInfo ;
ConfigurationElementProperty elementProperty ;
Configuration _configuration ;
bool elementPresent ;
internal Configuration Configuration {
get { return _configuration ; }
set { _configuration = value ; }
}
protected ConfigurationElement ( )
{
}
internal virtual void InitFromProperty ( PropertyInformation propertyInfo )
{
elementInfo = new ElementInformation ( this , propertyInfo ) ;
Init ( ) ;
}
public ElementInformation ElementInformation {
get {
if ( elementInfo = = null )
elementInfo = new ElementInformation ( this , null ) ;
return elementInfo ;
}
}
internal string RawXml {
get { return rawXml ; }
set {
// FIXME: this hack is nasty. We should make
// some refactory on the entire assembly.
if ( rawXml = = null | | value ! = null )
rawXml = value ;
}
}
protected internal virtual void Init ( )
{
}
protected internal virtual ConfigurationElementProperty ElementProperty {
get {
if ( elementProperty = = null )
elementProperty = new ConfigurationElementProperty ( ElementInformation . Validator ) ;
return elementProperty ;
}
}
protected ContextInformation EvaluationContext {
get {
if ( Configuration ! = null )
return Configuration . EvaluationContext ;
throw new ConfigurationErrorsException (
"This element is not currently associated with any context." ) ;
}
}
ConfigurationLockCollection lockAllAttributesExcept ;
public ConfigurationLockCollection LockAllAttributesExcept {
get {
if ( lockAllAttributesExcept = = null ) {
lockAllAttributesExcept = new ConfigurationLockCollection ( this , ConfigurationLockType . Attribute | ConfigurationLockType . Exclude ) ;
}
return lockAllAttributesExcept ;
}
}
ConfigurationLockCollection lockAllElementsExcept ;
public ConfigurationLockCollection LockAllElementsExcept {
get {
if ( lockAllElementsExcept = = null ) {
lockAllElementsExcept = new ConfigurationLockCollection ( this , ConfigurationLockType . Element | ConfigurationLockType . Exclude ) ;
}
return lockAllElementsExcept ;
}
}
ConfigurationLockCollection lockAttributes ;
public ConfigurationLockCollection LockAttributes {
get {
if ( lockAttributes = = null ) {
lockAttributes = new ConfigurationLockCollection ( this , ConfigurationLockType . Attribute ) ;
}
return lockAttributes ;
}
}
ConfigurationLockCollection lockElements ;
public ConfigurationLockCollection LockElements {
get {
if ( lockElements = = null ) {
lockElements = new ConfigurationLockCollection ( this , ConfigurationLockType . Element ) ;
}
return lockElements ;
}
}
bool lockItem ;
public bool LockItem {
get { return lockItem ; }
set { lockItem = value ; }
}
[MonoTODO]
2017-06-07 13:16:24 +00:00
protected virtual void ListErrors ( IList errorList )
2014-08-13 10:39:27 +01:00
{
throw new NotImplementedException ( ) ;
}
[MonoTODO]
protected void SetPropertyValue ( ConfigurationProperty prop , object value , bool ignoreLocks )
{
try {
if ( value ! = null ) {
/* XXX all i know for certain is that Validation happens here */
prop . Validate ( value ) ;
/ * XXX presumably the actual setting of the
* property happens here instead of in the
* set_Item code below , but that would mean
* the Value needs to be stuffed in the
* property , not the propertyinfo ( or else the
* property needs a ref to the property info
* to correctly set the value ) . * /
}
}
catch ( Exception e ) {
throw new ConfigurationErrorsException ( String . Format ( "The value for the property '{0}' on type {1} is not valid." , prop . Name , this . ElementInformation . Type ) , e ) ;
}
}
internal ConfigurationPropertyCollection GetKeyProperties ( )
{
if ( keyProps ! = null ) return keyProps ;
ConfigurationPropertyCollection tmpkeyProps = new ConfigurationPropertyCollection ( ) ;
foreach ( ConfigurationProperty prop in Properties ) {
if ( prop . IsKey )
tmpkeyProps . Add ( prop ) ;
}
return keyProps = tmpkeyProps ;
}
internal ConfigurationElementCollection GetDefaultCollection ( )
{
if ( defaultCollection ! = null ) return defaultCollection ;
ConfigurationProperty defaultCollectionProp = null ;
foreach ( ConfigurationProperty prop in Properties ) {
if ( prop . IsDefaultCollection ) {
defaultCollectionProp = prop ;
break ;
}
}
if ( defaultCollectionProp ! = null ) {
defaultCollection = this [ defaultCollectionProp ] as ConfigurationElementCollection ;
}
return defaultCollection ;
}
2017-06-07 13:16:24 +00:00
protected internal object this [ ConfigurationProperty prop ] {
get { return this [ prop . Name ] ; }
set { this [ prop . Name ] = value ; }
2014-08-13 10:39:27 +01:00
}
2017-06-07 13:16:24 +00:00
protected internal object this [ string propertyName ] {
2014-08-13 10:39:27 +01:00
get {
2017-06-07 13:16:24 +00:00
PropertyInformation pi = ElementInformation . Properties [ propertyName ] ;
2014-08-13 10:39:27 +01:00
if ( pi = = null )
2017-06-07 13:16:24 +00:00
throw new InvalidOperationException ( "Property '" + propertyName + "' not found in configuration element" ) ;
2014-08-13 10:39:27 +01:00
return pi . Value ;
}
set {
2017-06-07 13:16:24 +00:00
PropertyInformation pi = ElementInformation . Properties [ propertyName ] ;
2014-08-13 10:39:27 +01:00
if ( pi = = null )
2017-06-07 13:16:24 +00:00
throw new InvalidOperationException ( "Property '" + propertyName + "' not found in configuration element" ) ;
2014-08-13 10:39:27 +01:00
SetPropertyValue ( pi . Property , value , false ) ;
pi . Value = value ;
modified = true ;
}
}
protected internal virtual ConfigurationPropertyCollection Properties {
get {
if ( map = = null )
map = ElementMap . GetMap ( GetType ( ) ) ;
return map . Properties ;
}
}
public override bool Equals ( object compareTo )
{
ConfigurationElement other = compareTo as ConfigurationElement ;
if ( other = = null ) return false ;
if ( GetType ( ) ! = other . GetType ( ) ) return false ;
foreach ( ConfigurationProperty prop in Properties ) {
if ( ! object . Equals ( this [ prop ] , other [ prop ] ) )
return false ;
}
return true ;
}
public override int GetHashCode ( )
{
int code = 0 ;
object o ;
foreach ( ConfigurationProperty prop in Properties ) {
o = this [ prop ] ;
if ( o = = null )
continue ;
code + = o . GetHashCode ( ) ;
}
return code ;
}
internal virtual bool HasLocalModifications ( )
{
foreach ( PropertyInformation pi in ElementInformation . Properties )
if ( pi . ValueOrigin = = PropertyValueOrigin . SetHere & & pi . IsModified )
return true ;
return false ;
}
protected internal virtual void DeserializeElement ( XmlReader reader , bool serializeCollectionKey )
{
Hashtable readProps = new Hashtable ( ) ;
reader . MoveToContent ( ) ;
elementPresent = true ;
while ( reader . MoveToNextAttribute ( ) )
{
PropertyInformation prop = ElementInformation . Properties [ reader . LocalName ] ;
if ( prop = = null | | ( serializeCollectionKey & & ! prop . IsKey ) ) {
/* handle the built in ConfigurationElement attributes here */
if ( reader . LocalName = = "lockAllAttributesExcept" ) {
LockAllAttributesExcept . SetFromList ( reader . Value ) ;
}
else if ( reader . LocalName = = "lockAllElementsExcept" ) {
LockAllElementsExcept . SetFromList ( reader . Value ) ;
}
else if ( reader . LocalName = = "lockAttributes" ) {
LockAttributes . SetFromList ( reader . Value ) ;
}
else if ( reader . LocalName = = "lockElements" ) {
LockElements . SetFromList ( reader . Value ) ;
}
else if ( reader . LocalName = = "lockItem" ) {
LockItem = ( reader . Value . ToLowerInvariant ( ) = = "true" ) ;
}
else if ( reader . LocalName = = "xmlns" ) {
/* ignore */
} else if ( this is ConfigurationSection & & reader . LocalName = = "configSource" ) {
/* ignore */
} else if ( ! OnDeserializeUnrecognizedAttribute ( reader . LocalName , reader . Value ) )
throw new ConfigurationErrorsException ( "Unrecognized attribute '" + reader . LocalName + "'." , reader ) ;
continue ;
}
if ( readProps . ContainsKey ( prop ) )
throw new ConfigurationErrorsException ( "The attribute '" + prop . Name + "' may only appear once in this element." , reader ) ;
string value = null ;
try {
value = reader . Value ;
ValidateValue ( prop . Property , value ) ;
prop . SetStringValue ( value ) ;
} catch ( ConfigurationErrorsException ) {
throw ;
} catch ( ConfigurationException ) {
throw ;
} catch ( Exception ex ) {
string msg = String . Format ( "The value for the property '{0}' is not valid. The error is: {1}" , prop . Name , ex . Message ) ;
throw new ConfigurationErrorsException ( msg , reader ) ;
}
readProps [ prop ] = prop . Name ;
ConfigXmlTextReader _reader = reader as ConfigXmlTextReader ;
if ( _reader ! = null ) {
prop . Source = _reader . Filename ;
prop . LineNumber = _reader . LineNumber ;
}
}
reader . MoveToElement ( ) ;
if ( reader . IsEmptyElement ) {
reader . Skip ( ) ;
} else {
int depth = reader . Depth ;
reader . ReadStartElement ( ) ;
reader . MoveToContent ( ) ;
do {
if ( reader . NodeType ! = XmlNodeType . Element ) {
reader . Skip ( ) ;
continue ;
}
PropertyInformation prop = ElementInformation . Properties [ reader . LocalName ] ;
if ( prop = = null | | ( serializeCollectionKey & & ! prop . IsKey ) ) {
if ( ! OnDeserializeUnrecognizedElement ( reader . LocalName , reader ) ) {
if ( prop = = null ) {
ConfigurationElementCollection c = GetDefaultCollection ( ) ;
if ( c ! = null & & c . OnDeserializeUnrecognizedElement ( reader . LocalName , reader ) )
continue ;
}
throw new ConfigurationErrorsException ( "Unrecognized element '" + reader . LocalName + "'." , reader ) ;
}
continue ;
}
if ( ! prop . IsElement )
throw new ConfigurationErrorsException ( "Property '" + prop . Name + "' is not a ConfigurationElement." ) ;
if ( readProps . Contains ( prop ) )
throw new ConfigurationErrorsException ( "The element <" + prop . Name + "> may only appear once in this section." , reader ) ;
ConfigurationElement val = ( ConfigurationElement ) prop . Value ;
val . DeserializeElement ( reader , serializeCollectionKey ) ;
readProps [ prop ] = prop . Name ;
if ( depth = = reader . Depth )
reader . Read ( ) ;
} while ( depth < reader . Depth ) ;
}
modified = false ;
foreach ( PropertyInformation prop in ElementInformation . Properties )
if ( ! String . IsNullOrEmpty ( prop . Name ) & & prop . IsRequired & & ! readProps . ContainsKey ( prop ) ) {
PropertyInformation p = ElementInformation . Properties [ prop . Name ] ;
if ( p = = null ) {
object val = OnRequiredPropertyNotFound ( prop . Name ) ;
if ( ! object . Equals ( val , prop . DefaultValue ) ) {
prop . Value = val ;
prop . IsModified = false ;
}
}
}
PostDeserialize ( ) ;
}
protected virtual bool OnDeserializeUnrecognizedAttribute ( string name , string value )
{
return false ;
}
2017-06-07 13:16:24 +00:00
protected virtual bool OnDeserializeUnrecognizedElement ( string elementName , XmlReader reader )
2014-08-13 10:39:27 +01:00
{
return false ;
}
protected virtual object OnRequiredPropertyNotFound ( string name )
{
throw new ConfigurationErrorsException ( "Required attribute '" + name + "' not found." ) ;
}
protected virtual void PreSerialize ( XmlWriter writer )
{
}
protected virtual void PostDeserialize ( )
{
}
protected internal virtual void InitializeDefault ( )
{
}
protected internal virtual bool IsModified ( )
{
if ( modified )
return true ;
foreach ( PropertyInformation prop in ElementInformation . Properties ) {
if ( ! prop . IsElement )
continue ;
var element = prop . Value as ConfigurationElement ;
if ( ( element = = null ) | | ! element . IsModified ( ) )
continue ;
modified = true ;
break ;
}
return modified ;
}
protected internal virtual void SetReadOnly ( )
{
readOnly = true ;
}
public virtual bool IsReadOnly ( )
{
return readOnly ;
}
protected internal virtual void Reset ( ConfigurationElement parentElement )
{
elementPresent = false ;
if ( parentElement ! = null )
ElementInformation . Reset ( parentElement . ElementInformation ) ;
else
InitializeDefault ( ) ;
}
protected internal virtual void ResetModified ( )
{
modified = false ;
foreach ( PropertyInformation p in ElementInformation . Properties ) {
p . IsModified = false ;
var element = p . Value as ConfigurationElement ;
if ( element ! = null )
element . ResetModified ( ) ;
}
}
protected internal virtual bool SerializeElement ( XmlWriter writer , bool serializeCollectionKey )
{
PreSerialize ( writer ) ;
if ( serializeCollectionKey ) {
ConfigurationPropertyCollection props = GetKeyProperties ( ) ;
foreach ( ConfigurationProperty prop in props )
writer . WriteAttributeString ( prop . Name , prop . ConvertToString ( this [ prop . Name ] ) ) ;
return props . Count > 0 ;
}
bool wroteData = false ;
foreach ( PropertyInformation prop in ElementInformation . Properties )
{
if ( prop . IsElement )
continue ;
if ( saveContext = = null )
throw new InvalidOperationException ( ) ;
if ( ! saveContext . HasValue ( prop ) )
continue ;
writer . WriteAttributeString ( prop . Name , prop . GetStringValue ( ) ) ;
wroteData = true ;
}
foreach ( PropertyInformation prop in ElementInformation . Properties )
{
if ( ! prop . IsElement )
continue ;
ConfigurationElement val = ( ConfigurationElement ) prop . Value ;
if ( val ! = null )
wroteData = val . SerializeToXmlElement ( writer , prop . Name ) | | wroteData ;
}
return wroteData ;
}
protected internal virtual bool SerializeToXmlElement (
XmlWriter writer , string elementName )
{
if ( saveContext = = null )
throw new InvalidOperationException ( ) ;
if ( ! saveContext . HasValues ( ) )
return false ;
if ( elementName ! = null & & elementName ! = "" )
writer . WriteStartElement ( elementName ) ;
bool res = SerializeElement ( writer , false ) ;
if ( elementName ! = null & & elementName ! = "" )
writer . WriteEndElement ( ) ;
return res ;
}
protected internal virtual void Unmerge (
2017-06-07 13:16:24 +00:00
ConfigurationElement sourceElement , ConfigurationElement parentElement ,
ConfigurationSaveMode saveMode )
2014-08-13 10:39:27 +01:00
{
2017-06-07 13:16:24 +00:00
if ( parentElement ! = null & & sourceElement . GetType ( ) ! = parentElement . GetType ( ) )
2014-08-13 10:39:27 +01:00
throw new ConfigurationErrorsException ( "Can't unmerge two elements of different type" ) ;
2017-06-07 13:16:24 +00:00
bool isMinimalOrModified = saveMode = = ConfigurationSaveMode . Minimal | |
saveMode = = ConfigurationSaveMode . Modified ;
2014-08-13 10:39:27 +01:00
2017-06-07 13:16:24 +00:00
foreach ( PropertyInformation prop in sourceElement . ElementInformation . Properties )
2014-08-13 10:39:27 +01:00
{
if ( prop . ValueOrigin = = PropertyValueOrigin . Default )
continue ;
PropertyInformation unmergedProp = ElementInformation . Properties [ prop . Name ] ;
object sourceValue = prop . Value ;
2017-06-07 13:16:24 +00:00
if ( parentElement = = null | | ! parentElement . HasValue ( prop . Name ) ) {
2014-08-13 10:39:27 +01:00
unmergedProp . Value = sourceValue ;
continue ;
}
if ( sourceValue = = null )
continue ;
2017-06-07 13:16:24 +00:00
object parentValue = parentElement [ prop . Name ] ;
2014-08-13 10:39:27 +01:00
if ( ! prop . IsElement ) {
if ( ! object . Equals ( sourceValue , parentValue ) | |
2017-06-07 13:16:24 +00:00
( saveMode = = ConfigurationSaveMode . Full ) | |
( saveMode = = ConfigurationSaveMode . Modified & & prop . ValueOrigin = = PropertyValueOrigin . SetHere ) )
2014-08-13 10:39:27 +01:00
unmergedProp . Value = sourceValue ;
continue ;
}
2017-06-07 13:16:24 +00:00
var sourceElementValue = ( ConfigurationElement ) sourceValue ;
if ( isMinimalOrModified & & ! sourceElementValue . IsModified ( ) )
2014-08-13 10:39:27 +01:00
continue ;
if ( parentValue = = null ) {
unmergedProp . Value = sourceValue ;
continue ;
}
2017-06-07 13:16:24 +00:00
var parentElementValue = ( ConfigurationElement ) parentValue ;
2014-08-13 10:39:27 +01:00
ConfigurationElement copy = ( ConfigurationElement ) unmergedProp . Value ;
2017-06-07 13:16:24 +00:00
copy . Unmerge ( sourceElementValue , parentElementValue , saveMode ) ;
2014-08-13 10:39:27 +01:00
}
}
internal bool HasValue ( string propName )
{
PropertyInformation info = ElementInformation . Properties [ propName ] ;
return info ! = null & & info . ValueOrigin ! = PropertyValueOrigin . Default ;
}
internal bool IsReadFromConfig ( string propName )
{
PropertyInformation info = ElementInformation . Properties [ propName ] ;
return info ! = null & & info . ValueOrigin = = PropertyValueOrigin . SetHere ;
}
internal bool IsElementPresent
{
get { return elementPresent ; }
}
void ValidateValue ( ConfigurationProperty p , string value )
{
ConfigurationValidatorBase validator ;
if ( p = = null | | ( validator = p . Validator ) = = null )
return ;
if ( ! validator . CanValidate ( p . Type ) )
throw new ConfigurationErrorsException (
String . Format ( "Validator does not support type {0}" , p . Type ) ) ;
validator . Validate ( p . ConvertFromString ( value ) ) ;
}
/ *
* FIXME : LAMESPEC
*
* SerializeElement ( ) and SerializeToXmlElement ( ) need to emit different output
* based on the ConfigurationSaveMode that ' s being used . Unfortunately , neither
* of these methods take it as an argument and there seems to be no documented way
* how to get it .
*
* The parent element is needed because the element could be set to a different
* than the default value in a parent configuration file , then set locally to that
* same value . This makes the element appear locally modified ( so it ' s included
* with ConfigurationSaveMode . Modified ) , but it should not be emitted with
* ConfigurationSaveMode . Minimal .
*
* In theory , we could save it into some private field in Unmerge ( ) , but the
* problem is that Unmerge ( ) is kinda expensive and we also need a way of
* determining whether or not the configuration has changed in Configuration . Save ( ) ,
* prior to opening the output file for writing .
*
* There are two places from where HasValues ( ) is called :
* a ) From Configuration . Save ( ) / SaveAs ( ) to check whether the configuration needs
* to be saved . This check is done prior to opening the file for writing .
* b ) From SerializeToXmlElement ( ) to check whether to emit the element , using the
* parent and mode values from the cached ' SaveContext ' .
*
* /
/ *
* Check whether property ' prop ' should be included in the serialized XML
* based on the current ConfigurationSaveMode .
* /
internal bool HasValue ( ConfigurationElement parent , PropertyInformation prop ,
ConfigurationSaveMode mode )
{
if ( prop . ValueOrigin = = PropertyValueOrigin . Default )
return false ;
if ( mode = = ConfigurationSaveMode . Modified & &
prop . ValueOrigin = = PropertyValueOrigin . SetHere & & prop . IsModified ) {
// Value has been modified locally, so we always emit it
// with ConfigurationSaveMode.Modified.
return true ;
}
/ *
* Ok , now we have to check whether we ' re different from the inherited
* value - which could either be a value that ' s set in a parent
* configuration file or the default value .
* /
var hasParentValue = parent ! = null & & parent . HasValue ( prop . Name ) ;
var parentOrDefault = hasParentValue ? parent [ prop . Name ] : prop . DefaultValue ;
if ( ! prop . IsElement )
return ! object . Equals ( prop . Value , parentOrDefault ) ;
/ *
* Ok , it ' s an element that has been set in a parent configuration file . *
* Recursively call HasValues ( ) to check whether it ' s been locally modified .
* /
var element = ( ConfigurationElement ) prop . Value ;
var parentElement = ( ConfigurationElement ) parentOrDefault ;
return element . HasValues ( parentElement , mode ) ;
}
/ *
* Check whether this element should be included in the serialized XML
* based on the current ConfigurationSaveMode .
*
* The ' parent ' value is needed to determine whether the element currently
* has a different value from what ' s been set in the parent configuration
* hierarchy .
* /
internal virtual bool HasValues ( ConfigurationElement parent , ConfigurationSaveMode mode )
{
if ( mode = = ConfigurationSaveMode . Full )
return true ;
if ( modified & & ( mode = = ConfigurationSaveMode . Modified ) )
return true ;
foreach ( PropertyInformation prop in ElementInformation . Properties ) {
if ( HasValue ( parent , prop , mode ) )
return true ;
}
return false ;
}
/ *
* Cache the current ' parent ' and ' mode ' values for later use in SerializeToXmlElement ( )
* and SerializeElement ( ) .
*
* Make sure to call base when overriding this in a derived class .
* /
internal virtual void PrepareSave ( ConfigurationElement parent , ConfigurationSaveMode mode )
{
saveContext = new SaveContext ( this , parent , mode ) ;
foreach ( PropertyInformation prop in ElementInformation . Properties )
{
if ( ! prop . IsElement )
continue ;
var elem = ( ConfigurationElement ) prop . Value ;
if ( parent = = null | | ! parent . HasValue ( prop . Name ) )
elem . PrepareSave ( null , mode ) ;
else {
var parentValue = ( ConfigurationElement ) parent [ prop . Name ] ;
elem . PrepareSave ( parentValue , mode ) ;
}
}
}
SaveContext saveContext ;
class SaveContext {
public readonly ConfigurationElement Element ;
public readonly ConfigurationElement Parent ;
public readonly ConfigurationSaveMode Mode ;
public SaveContext ( ConfigurationElement element , ConfigurationElement parent ,
ConfigurationSaveMode mode )
{
this . Element = element ;
this . Parent = parent ;
this . Mode = mode ;
}
public bool HasValues ( )
{
if ( Mode = = ConfigurationSaveMode . Full )
return true ;
return Element . HasValues ( Parent , Mode ) ;
}
public bool HasValue ( PropertyInformation prop )
{
if ( Mode = = ConfigurationSaveMode . Full )
return true ;
return Element . HasValue ( Parent , prop , Mode ) ;
}
}
}
internal class ElementMap
{
static readonly Hashtable elementMaps = Hashtable . Synchronized ( new Hashtable ( ) ) ;
readonly ConfigurationPropertyCollection properties ;
readonly ConfigurationCollectionAttribute collectionAttribute ;
public static ElementMap GetMap ( Type t )
{
ElementMap map = elementMaps [ t ] as ElementMap ;
if ( map ! = null ) return map ;
map = new ElementMap ( t ) ;
elementMaps [ t ] = map ;
return map ;
}
public ElementMap ( Type t )
{
properties = new ConfigurationPropertyCollection ( ) ;
collectionAttribute = Attribute . GetCustomAttribute ( t , typeof ( ConfigurationCollectionAttribute ) ) as ConfigurationCollectionAttribute ;
PropertyInfo [ ] props = t . GetProperties ( BindingFlags . Public | BindingFlags . NonPublic | BindingFlags . Static | BindingFlags . Instance ) ;
foreach ( PropertyInfo prop in props )
{
ConfigurationPropertyAttribute at = Attribute . GetCustomAttribute ( prop , typeof ( ConfigurationPropertyAttribute ) ) as ConfigurationPropertyAttribute ;
if ( at = = null ) continue ;
string name = at . Name ! = null ? at . Name : prop . Name ;
ConfigurationValidatorAttribute validatorAttr = Attribute . GetCustomAttribute ( prop , typeof ( ConfigurationValidatorAttribute ) ) as ConfigurationValidatorAttribute ;
ConfigurationValidatorBase validator = validatorAttr ! = null ? validatorAttr . ValidatorInstance : null ;
TypeConverterAttribute convertAttr = ( TypeConverterAttribute ) Attribute . GetCustomAttribute ( prop , typeof ( TypeConverterAttribute ) ) ;
TypeConverter converter = convertAttr ! = null ? ( TypeConverter ) Activator . CreateInstance ( Type . GetType ( convertAttr . ConverterTypeName ) , true ) : null ;
ConfigurationProperty cp = new ConfigurationProperty ( name , prop . PropertyType , at . DefaultValue , converter , validator , at . Options ) ;
cp . CollectionAttribute = Attribute . GetCustomAttribute ( prop , typeof ( ConfigurationCollectionAttribute ) ) as ConfigurationCollectionAttribute ;
properties . Add ( cp ) ;
}
}
public ConfigurationCollectionAttribute CollectionAttribute
{
get { return collectionAttribute ; }
}
public bool HasProperties
{
get { return properties . Count > 0 ; }
}
public ConfigurationPropertyCollection Properties
{
get {
return properties ;
}
}
}
}