| File: Serialization\Manager\ReachSerializableProperties.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\ReachFramework\ReachFramework.csproj (ReachFramework) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. /*++ Abstract: Defining some classes encapsulating some information about the properties contained within an object and used in the serialization process --*/ using System.Collections; using System.ComponentModel; using System.Reflection; using System.Windows.Markup; namespace System.Windows.Xps.Serialization { internal class SerializablePropertyCollection : IEnumerable, IEnumerator { #region Contstructor /// <summary> /// Intantiate a SerializablePropertyCollection /// </summary> internal SerializablePropertyCollection( PackageSerializationManager manager, object targetObject ) { this._simplePropertyCollection = null; this._complexPropertyCollection = null; this._simplePropertiesIndex = -1; this._complexPropertiesIndex = -1; this._queueEnumerator = null; this._serializationManager = manager; this._target = targetObject; this._isSimpleMode = true; Initialize(manager, _target); } #endregion Constructor #region IEnumerable implementation /// <summary> /// return the Enumerator for the collection /// </summary> public IEnumerator GetEnumerator( ) { return this; } #endregion IEnumerable implementation #region IEnumerator implementation /// <summary> /// Current object in the collection /// </summary> public object Current { get { return _queueEnumerator.Current; } } /// <summary> /// Move to the next PropertyContext /// </summary> public bool MoveNext() { bool canMoveToNext = false; if(_isSimpleMode) { if(_simplePropertiesIndex == -1) { _queueEnumerator = _simplePropertyCollection.GetEnumerator(); } if(_simplePropertiesIndex < _simplePropertyCollection.Count-1) { _simplePropertiesIndex++; _queueEnumerator.MoveNext(); canMoveToNext = true; } else { _isSimpleMode = false; } } if(!_isSimpleMode) { if(_complexPropertiesIndex == -1) { _queueEnumerator = _complexPropertyCollection.GetEnumerator(); } if(_complexPropertiesIndex < _complexPropertyCollection.Count-1) { _complexPropertiesIndex++; _queueEnumerator.MoveNext(); canMoveToNext = true; } } return canMoveToNext; } /// <summary> /// Reset all necessary indices and pointers to /// the beginning of the collection /// </summary> public void Reset( ) { this._simplePropertiesIndex = -1; this._complexPropertiesIndex = -1; this._queueEnumerator = null; this._isSimpleMode = true; } #endregion IEnumerator implementation #region Internal Methods /// <summary> /// Initialize this instance /// </summary> internal void Initialize( PackageSerializationManager serializationManager, object targetObject ) { this._serializationManager = serializationManager; this._target = targetObject; // // Collect all serializable properties on the // current object instance. Those could be // o clr properties // o dependency properties // if (_simplePropertyCollection == null) { _simplePropertyCollection = new Queue(); } if (_complexPropertyCollection == null) { _complexPropertyCollection = new Queue(); } // // Collecting information about the CLR properties // InitializeSerializableClrProperties(); // // Now that we are done with the clr serializable properties we need to // iterate through locally set dependency properties on this instance // that have not been serialized already. // Note: Dependency Properties can only be set on Dependency Objects // InitializeSerializableDependencyProperties(); // // Reset the enumerator // to begin enumerating // from the start of the // properties collection // Reset(); } /// <summary> /// Clear all references for reuse without /// instantiation. This is a way of caching /// already instantiated through recycling /// for future use. /// </summary> internal void Clear() { this._simplePropertyCollection.Clear(); this._complexPropertyCollection.Clear(); this._simplePropertiesIndex = -1; this._complexPropertiesIndex = -1; this._queueEnumerator = null; this._serializationManager = null; this._target = null; this._isSimpleMode = true; } #endregion Internal Methods #region Private Methods /// <summary> /// Fill out the portion of the collection which /// points out to the CLR properties /// </summary> private void InitializeSerializableClrProperties( ) { TypePropertyCache[] clrProperties = _serializationManager.CacheManager.GetClrSerializableProperties(_target); if(clrProperties!=null) { for (int indexInClrSerializableProperties=0; indexInClrSerializableProperties < clrProperties.Length; indexInClrSerializableProperties++) { TypePropertyCache propertyCache = clrProperties[indexInClrSerializableProperties]; // // Create SerializablePropertyContext out of the cache retrieved // SerializablePropertyContext propertyContext = new SerializablePropertyContext(_target, propertyCache); propertyContext.Name = propertyContext.TypePropertyCache.PropertyInfo.Name; // // We have to differentiate between simple properties and complex properties. // o Simple properties would be considered as attributes within the markup and // would not require new writers // o Complex properties would be considered elements within the markup and might // require a new writer // if(propertyContext.IsComplexProperty(_serializationManager)) { propertyContext.IsComplex = true; _complexPropertyCollection.Enqueue(propertyContext); } else { propertyContext.IsComplex = false; _simplePropertyCollection.Enqueue(propertyContext); } } } } /// <summary> /// Fill out the portion of the collection /// that points out to the dependency properties /// </summary> private void InitializeSerializableDependencyProperties( ) { TypeDependencyPropertyCache[] dependencyProperties = _serializationManager. CacheManager. GetSerializableDependencyProperties(_target); if(dependencyProperties!=null) { for (int indexInSerializableDependencyProperties=0; indexInSerializableDependencyProperties < dependencyProperties.Length; indexInSerializableDependencyProperties++) { TypeDependencyPropertyCache dependencyPropertyCache = dependencyProperties[indexInSerializableDependencyProperties]; // // Create SerializableDependencyPropertyContext out of the cache retrieved // SerializableDependencyPropertyContext dependencyPropertyContext = new SerializableDependencyPropertyContext(_target, dependencyPropertyCache); dependencyPropertyContext.Name = ((DependencyProperty)((TypeDependencyPropertyCache)dependencyPropertyContext.TypePropertyCache). DependencyProperty).Name; // // We have to differentiate between simple properties and complex properties. // o Simple properties would be considered as attributes within the markup and // would not require new writers // o Complex properties would be considered elements within the markup and might // require a new writer // if(dependencyPropertyContext.IsComplexProperty(_serializationManager)) { dependencyPropertyContext.IsComplex = true; _complexPropertyCollection.Enqueue(dependencyPropertyContext); } else { dependencyPropertyContext.IsComplex = false; _simplePropertyCollection.Enqueue(dependencyPropertyContext); } } } } #endregion Private Methods #region Private Data private PackageSerializationManager _serializationManager; private object _target; private bool _isSimpleMode; private int _simplePropertiesIndex; private Queue _simplePropertyCollection; private int _complexPropertiesIndex; private Queue _complexPropertyCollection; private IEnumerator _queueEnumerator; #endregion Private Data }; /// <summary> /// A class defining a context for the serializable CLR property /// </summary> internal class SerializablePropertyContext : BasicContext { #region Constructor /// <summary> /// Constructor for SerializablePropertyContext /// </summary> public SerializablePropertyContext( string name, string prefix, object target, TypePropertyCache propertyCache) : base(name, prefix) { // // Validate Input Arguments // ArgumentNullException.ThrowIfNull(target); ArgumentNullException.ThrowIfNull(propertyCache); this._targetObject = target; this._propertyInfo = propertyCache; this._isComplex = false; } /// <summary> /// Constructor for SerializablePropertyContext /// </summary> internal SerializablePropertyContext( object target, TypePropertyCache propertyCache) : base() { // // Validate Input Arguments // ArgumentNullException.ThrowIfNull(target); ArgumentNullException.ThrowIfNull(propertyCache); _targetObject = target; _propertyInfo = propertyCache; this._isComplex = false; } #endregion Constructor #region Public Methods /// <summary> /// Detect whether it is a complex property or not. /// </summary> public virtual bool IsComplexProperty( PackageSerializationManager serializationManager ) { bool isComplex = false; // // Null property value is always serialized // in simple attribute="*null" notation // if (Value != null) { // // If the property has a DesignerSerializationOptions.SerializeAsAttribute // then obviously we do not use complex notation // if(!(DesignerSerializationOptionsAttribute != null && (DesignerSerializationOptionsAttribute.DesignerSerializationOptions == DesignerSerializationOptions.SerializeAsAttribute))) { // // String space preservation is honoured by System.Xml only for contents of a tag not within // an attribute value. Hence we always emit strings as content within a tag // Type valueType = Value.GetType(); if (valueType == typeof(string) && ((string)Value) != string.Empty) { isComplex = true; } else { bool canConvert; isComplex = IsComplexValue(serializationManager, out canConvert); } } } return isComplex; } public virtual bool IsComplexValue( PackageSerializationManager manager, out bool canConvert ) { bool isComplex = true; canConvert = true; if(SerializerType!=null) { isComplex = true; } else { TypeConverter converter = this.TypeConverter; canConvert = converter.CanConvertTo(null,typeof(string)) && converter.CanConvertFrom(null,typeof(string)); if(canConvert) { isComplex = false; } } return isComplex; } #endregion Public Methods #region Public Properties /// <summary> /// Qyery the Target Object /// </summary> public object TargetObject { get { return _targetObject; } } /// <summary> /// Qyery the CLR propertyInfo structure of this property /// </summary> public PropertyInfo PropertyInfo { get { PropertyInfo info = null; if (_propertyInfo != null) { info = (PropertyInfo)_propertyInfo.PropertyInfo; } return info; } } // <summary> // Query / Set whether the property is Complex / Simple // </summary> public bool IsComplex { get { return _isComplex; } set { _isComplex = value; } } /// <summary> /// Query the visibility of the property /// </summary> public DesignerSerializationVisibility Visibility { get { DesignerSerializationVisibility visibility = DesignerSerializationVisibility.Visible; if (_propertyInfo != null) { visibility = _propertyInfo.Visibility; } return visibility; } } /// <summary> /// Queries the Serializer type used to serialize this /// property if it happens to be a complex property /// </summary> public Type SerializerType { get { Type type = null; if (_propertyInfo != null) { type = _propertyInfo.SerializerTypeForProperty; } return type; } } /// <summary> /// Queries the TypeConverter used to convert this property /// to some equivalent string /// </summary> public TypeConverter TypeConverter { get { TypeConverter converter = null; if (_propertyInfo != null) { converter = _propertyInfo.TypeConverterForProperty; } return converter; } } /// <summary> /// Query the default value attribute /// </summary> public DefaultValueAttribute DefaultValueAttribute { get { DefaultValueAttribute defValAttr = null; if (_propertyInfo != null) { defValAttr = _propertyInfo.DefaultValueAttr; } return defValAttr; } } /// <summary> /// Query the serialization attributes /// </summary> public DesignerSerializationOptionsAttribute DesignerSerializationOptionsAttribute { get { DesignerSerializationOptionsAttribute designerSerFlagAttr = null; if (_propertyInfo != null) { designerSerFlagAttr = _propertyInfo.DesignerSerializationOptionsAttr; } return designerSerFlagAttr; } } /// <summary> /// Query whether this is a read only or a read/write property /// </summary> public bool IsReadOnly { get { bool isReadOnly = false; if ( (_propertyInfo != null) && (((PropertyInfo)_propertyInfo.PropertyInfo) != null) ) { isReadOnly = !((PropertyInfo)_propertyInfo.PropertyInfo).CanWrite; } return isReadOnly; } } /// <summary> /// Query / set the value of this property /// </summary> public object Value { get { return _propertyInfo.PropertyValue; } set { _propertyInfo.PropertyValue = value; } } /// <summary> /// This is the cache information about the property. Each /// property discovered is saved for performance optimization /// </summary> public TypePropertyCache TypePropertyCache { get { return _propertyInfo; } } #endregion Public Properties #region Private Data private object _targetObject; private TypePropertyCache _propertyInfo; private bool _isComplex; #endregion Private Data }; /// <summary> /// A class defining context for serializable Dependency Properties /// </summary> internal class SerializableDependencyPropertyContext : SerializablePropertyContext { #region Constructor /// <summary> /// Constructor for SerializableDependencyPropertyContext /// </summary> public SerializableDependencyPropertyContext( string name, string prefix, object target, TypeDependencyPropertyCache propertyCache) : base(name, prefix,target,propertyCache) { } /// <summary> /// Constructor for SerializableDependencyPropertyContext /// </summary> public SerializableDependencyPropertyContext( object target, TypeDependencyPropertyCache propertyCache) : base(target,propertyCache) { } #endregion Constructor #region Public Methods /// <summary> /// Detects whether this property is complex or simple /// </summary> public override bool IsComplexProperty( PackageSerializationManager serializationManager ) { bool isComplex = false; // // Null property value is always serialized // in simple attribute="*null" notation // if (Value != null) { // // If the property has a DesignerSerializationOptions.SerializeAsAttribute // then obviously we do not use complex notation // if(!(DesignerSerializationOptionsAttribute != null && (DesignerSerializationOptionsAttribute.DesignerSerializationOptions == DesignerSerializationOptions.SerializeAsAttribute))) { // // String space preservation is honored by System.Xml only for contents of a tag not within // an attribute value. Hence we always emit strings as content within a tag // Type valueType = Value.GetType(); if (valueType == typeof(string) && ((string)Value) != string.Empty) { isComplex = true; } else { bool canConvert; isComplex = IsComplexValue(serializationManager, out canConvert); if (!canConvert) { Expression expr = this.Value as Expression; if (expr != null) { this.Value = ((DependencyObject)this.TargetObject).GetValue((DependencyProperty)this.DependencyProperty); isComplex = this.IsComplexProperty(serializationManager); } } } } } return isComplex; } public override bool IsComplexValue( PackageSerializationManager manager, out bool canConvert ) { bool isComplex = true; canConvert = true; if(SerializerType!=null) { isComplex = true; } else { TypeConverter converter = this.TypeConverter; canConvert = converter.CanConvertTo(null,typeof(string)) && converter.CanConvertFrom(null,typeof(string)); if(canConvert) { isComplex = false; } } return isComplex; } #endregion Public Methods #region Public Properties /// <summary> /// return info about the dependency property /// </summary> public MemberInfo MemberInfo { get { MemberInfo memberInfo = null; if (this.PropertyInfo != null) { memberInfo = ((TypeDependencyPropertyCache)TypePropertyCache).MemberInfo; } return memberInfo; } } /// <summary> /// return the dependency property /// </summary> public Object DependencyProperty { get { Object dependencyProperty = null; if (this.PropertyInfo != null) { dependencyProperty = ((TypeDependencyPropertyCache)TypePropertyCache).DependencyProperty; } return dependencyProperty; } } #endregion Public Properties }; }