The Labs \ Source Viewer \ SSCLI \ System.Xml.Serialization \ PrimitiveModel

  1. //------------------------------------------------------------------------------
  2. // <copyright file="Models.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. // <owner current="true" primary="true">ElenaK</owner>
  15. //------------------------------------------------------------------------------
  16. namespace System.Xml.Serialization
  17. {
  18.    
  19.     using System;
  20.     using System.Reflection;
  21.     using System.Collections;
  22.     using System.Diagnostics;
  23.    
  24.     // These classes define the abstract serialization model, e.g. the rules for WHAT is serialized.
  25.     // The answer of HOW the values are serialized is answered by a particular reflection importer
  26.     // by looking for a particular set of custom attributes specific to the serialization format
  27.     // and building an appropriate set of accessors/mappings.
  28.    
  29.     internal class ModelScope
  30.     {
  31.         TypeScope typeScope;
  32.         Hashtable models = new Hashtable();
  33.         Hashtable arrayModels = new Hashtable();
  34.        
  35.         internal ModelScope(TypeScope typeScope)
  36.         {
  37.             this.typeScope = typeScope;
  38.         }
  39.        
  40.         internal TypeScope TypeScope {
  41.             get { return typeScope; }
  42.         }
  43.        
  44.         internal TypeModel GetTypeModel(Type type)
  45.         {
  46.             return GetTypeModel(type, true);
  47.         }
  48.        
  49.         internal TypeModel GetTypeModel(Type type, bool directReference)
  50.         {
  51.             TypeModel model = (TypeModel)models[type];
  52.             if (model != null)
  53.                 return model;
  54.             TypeDesc typeDesc = typeScope.GetTypeDesc(type, null, directReference);
  55.            
  56.             switch (typeDesc.Kind) {
  57.                 case TypeKind.Enum:
  58.                     model = new EnumModel(type, typeDesc, this);
  59.                     break;
  60.                 case TypeKind.Primitive:
  61.                     model = new PrimitiveModel(type, typeDesc, this);
  62.                     break;
  63.                 case TypeKind.Array:
  64.                 case TypeKind.Collection:
  65.                 case TypeKind.Enumerable:
  66.                     model = new ArrayModel(type, typeDesc, this);
  67.                     break;
  68.                 case TypeKind.Root:
  69.                 case TypeKind.Class:
  70.                 case TypeKind.Struct:
  71.                     model = new StructModel(type, typeDesc, this);
  72.                     break;
  73.                 default:
  74.                     if (!typeDesc.IsSpecial)
  75.                         throw new NotSupportedException(Res.GetString(Res.XmlUnsupportedTypeKind, type.FullName));
  76.                     model = new SpecialModel(type, typeDesc, this);
  77.                     break;
  78.             }
  79.            
  80.             models.Add(type, model);
  81.             return model;
  82.         }
  83.        
  84.         internal ArrayModel GetArrayModel(Type type)
  85.         {
  86.             TypeModel model = (TypeModel)arrayModels[type];
  87.             if (model == null) {
  88.                 model = GetTypeModel(type);
  89.                 if (!(model is ArrayModel)) {
  90.                     TypeDesc typeDesc = typeScope.GetArrayTypeDesc(type);
  91.                     model = new ArrayModel(type, typeDesc, this);
  92.                 }
  93.                 arrayModels.Add(type, model);
  94.             }
  95.             return (ArrayModel)model;
  96.         }
  97.     }
  98.    
  99.     internal abstract class TypeModel
  100.     {
  101.         TypeDesc typeDesc;
  102.         Type type;
  103.         ModelScope scope;
  104.        
  105.         protected TypeModel(Type type, TypeDesc typeDesc, ModelScope scope)
  106.         {
  107.             this.scope = scope;
  108.             this.type = type;
  109.             this.typeDesc = typeDesc;
  110.         }
  111.        
  112.         internal Type Type {
  113.             get { return type; }
  114.         }
  115.        
  116.         internal ModelScope ModelScope {
  117.             get { return scope; }
  118.         }
  119.        
  120.         internal TypeDesc TypeDesc {
  121.             get { return typeDesc; }
  122.         }
  123.     }
  124.    
  125.     internal class ArrayModel : TypeModel
  126.     {
  127.         internal ArrayModel(Type type, TypeDesc typeDesc, ModelScope scope) : base(type, typeDesc, scope)
  128.         {
  129.         }
  130.        
  131.         internal TypeModel Element {
  132.             get { return ModelScope.GetTypeModel(TypeScope.GetArrayElementType(Type, null)); }
  133.         }
  134.     }
  135.    
  136.     internal class PrimitiveModel : TypeModel
  137.     {
  138.         internal PrimitiveModel(Type type, TypeDesc typeDesc, ModelScope scope) : base(type, typeDesc, scope)
  139.         {
  140.         }
  141.     }
  142.    
  143.     internal class SpecialModel : TypeModel
  144.     {
  145.         internal SpecialModel(Type type, TypeDesc typeDesc, ModelScope scope) : base(type, typeDesc, scope)
  146.         {
  147.         }
  148.     }
  149.    
  150.     internal class StructModel : TypeModel
  151.     {
  152.        
  153.         internal StructModel(Type type, TypeDesc typeDesc, ModelScope scope) : base(type, typeDesc, scope)
  154.         {
  155.         }
  156.        
  157.         internal MemberInfo[] GetMemberInfos()
  158.         {
  159.             MemberInfo[] members = Type.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
  160.             MemberInfo[] fieldsAndProps = new MemberInfo[members.Length];
  161.            
  162.             int cMember = 0;
  163.             // first copy all non-property members over
  164.             for (int i = 0; i < members.Length; i++) {
  165.                 if ((members[i].MemberType & MemberTypes.Property) == 0) {
  166.                     fieldsAndProps[cMember++] = members[i];
  167.                 }
  168.             }
  169.             // now copy all property members over
  170.             for (int i = 0; i < members.Length; i++) {
  171.                 if ((members[i].MemberType & MemberTypes.Property) != 0) {
  172.                     fieldsAndProps[cMember++] = members[i];
  173.                 }
  174.             }
  175.             return fieldsAndProps;
  176.         }
  177.        
  178.         internal FieldModel GetFieldModel(MemberInfo memberInfo)
  179.         {
  180.             FieldModel model = null;
  181.             if (memberInfo is FieldInfo)
  182.                 model = GetFieldModel((FieldInfo)memberInfo);
  183.             else if (memberInfo is PropertyInfo)
  184.                 model = GetPropertyModel((PropertyInfo)memberInfo);
  185.             if (model != null) {
  186.                 if (model.ReadOnly && model.FieldTypeDesc.Kind != TypeKind.Collection && model.FieldTypeDesc.Kind != TypeKind.Enumerable)
  187.                     return null;
  188.             }
  189.             return model;
  190.         }
  191.        
  192.         void CheckSupportedMember(TypeDesc typeDesc, MemberInfo member, Type type)
  193.         {
  194.             if (typeDesc == null)
  195.                 return;
  196.             if (typeDesc.IsUnsupported) {
  197.                 if (typeDesc.Exception == null) {
  198.                     typeDesc.Exception = new NotSupportedException(Res.GetString(Res.XmlSerializerUnsupportedType, typeDesc.FullName));
  199.                 }
  200.                 throw new InvalidOperationException(Res.GetString(Res.XmlSerializerUnsupportedMember, member.DeclaringType.FullName + "." + member.Name, type.FullName), typeDesc.Exception);
  201.                
  202.             }
  203.             CheckSupportedMember(typeDesc.BaseTypeDesc, member, type);
  204.             CheckSupportedMember(typeDesc.ArrayElementTypeDesc, member, type);
  205.         }
  206.        
  207.         FieldModel GetFieldModel(FieldInfo fieldInfo)
  208.         {
  209.             if (fieldInfo.IsStatic)
  210.                 return null;
  211.             if (fieldInfo.DeclaringType != Type)
  212.                 return null;
  213.            
  214.             TypeDesc typeDesc = ModelScope.TypeScope.GetTypeDesc(fieldInfo.FieldType, fieldInfo, true, false);
  215.             if (fieldInfo.IsInitOnly && typeDesc.Kind != TypeKind.Collection && typeDesc.Kind != TypeKind.Enumerable)
  216.                 return null;
  217.            
  218.             CheckSupportedMember(typeDesc, fieldInfo, fieldInfo.FieldType);
  219.             return new FieldModel(fieldInfo, fieldInfo.FieldType, typeDesc);
  220.         }
  221.        
  222.         FieldModel GetPropertyModel(PropertyInfo propertyInfo)
  223.         {
  224.             if (propertyInfo.DeclaringType != Type)
  225.                 return null;
  226.             if (CheckPropertyRead(propertyInfo)) {
  227.                 TypeDesc typeDesc = ModelScope.TypeScope.GetTypeDesc(propertyInfo.PropertyType, propertyInfo, true, false);
  228.                 if (!propertyInfo.CanWrite && typeDesc.Kind != TypeKind.Collection && typeDesc.Kind != TypeKind.Enumerable)
  229.                     return null;
  230.                 CheckSupportedMember(typeDesc, propertyInfo, propertyInfo.PropertyType);
  231.                 return new FieldModel(propertyInfo, propertyInfo.PropertyType, typeDesc);
  232.             }
  233.             return null;
  234.         }
  235.        
  236.         //CheckProperty
  237.         static internal bool CheckPropertyRead(PropertyInfo propertyInfo)
  238.         {
  239.             if (!propertyInfo.CanRead)
  240.                 return false;
  241.            
  242.             MethodInfo getMethod = propertyInfo.GetGetMethod();
  243.             if (getMethod.IsStatic)
  244.                 return false;
  245.             ParameterInfo[] parameters = getMethod.GetParameters();
  246.             if (parameters.Length > 0)
  247.                 return false;
  248.             return true;
  249.         }
  250.     }
  251.    
  252.    
  253.     internal class FieldModel
  254.     {
  255.         bool checkSpecified;
  256.         bool checkShouldPersist;
  257.         bool readOnly = false;
  258.         bool isProperty = false;
  259.         Type fieldType;
  260.         string name;
  261.         TypeDesc fieldTypeDesc;
  262.        
  263.         internal FieldModel(string name, Type fieldType, TypeDesc fieldTypeDesc, bool checkSpecified, bool checkShouldPersist) : this(name, fieldType, fieldTypeDesc, checkSpecified, checkShouldPersist, false)
  264.         {
  265.         }
  266.         internal FieldModel(string name, Type fieldType, TypeDesc fieldTypeDesc, bool checkSpecified, bool checkShouldPersist, bool readOnly)
  267.         {
  268.             this.fieldTypeDesc = fieldTypeDesc;
  269.             this.name = name;
  270.             this.fieldType = fieldType;
  271.             this.checkSpecified = checkSpecified;
  272.             this.checkShouldPersist = checkShouldPersist;
  273.             this.readOnly = readOnly;
  274.         }
  275.        
  276.         internal FieldModel(MemberInfo memberInfo, Type fieldType, TypeDesc fieldTypeDesc)
  277.         {
  278.             this.name = memberInfo.Name;
  279.             this.fieldType = fieldType;
  280.             this.fieldTypeDesc = fieldTypeDesc;
  281.             this.checkShouldPersist = memberInfo.DeclaringType.GetMethod("ShouldSerialize" + memberInfo.Name, new Type[0]) != null;
  282.            
  283.             FieldInfo specifiedField = memberInfo.DeclaringType.GetField(memberInfo.Name + "Specified");
  284.             if (specifiedField != null) {
  285.                 if (specifiedField.FieldType != typeof(bool)) {
  286.                     throw new InvalidOperationException(Res.GetString(Res.XmlInvalidSpecifiedType, specifiedField.Name, specifiedField.FieldType.FullName, typeof(bool).FullName));
  287.                 }
  288.                 this.checkSpecified = true;
  289.             }
  290.             else {
  291.                 PropertyInfo specifiedProperty = memberInfo.DeclaringType.GetProperty(memberInfo.Name + "Specified");
  292.                 if (specifiedProperty != null) {
  293.                     this.checkSpecified = StructModel.CheckPropertyRead(specifiedProperty);
  294.                     if (this.checkSpecified && specifiedProperty.PropertyType != typeof(bool)) {
  295.                         throw new InvalidOperationException(Res.GetString(Res.XmlInvalidSpecifiedType, specifiedProperty.Name, specifiedProperty.PropertyType.FullName, typeof(bool).FullName));
  296.                     }
  297.                 }
  298.             }
  299.             if (memberInfo is PropertyInfo) {
  300.                 readOnly = !((PropertyInfo)memberInfo).CanWrite;
  301.                 isProperty = true;
  302.             }
  303.             else if (memberInfo is FieldInfo) {
  304.                 readOnly = ((FieldInfo)memberInfo).IsInitOnly;
  305.             }
  306.         }
  307.        
  308.         internal string Name {
  309.             get { return name; }
  310.         }
  311.        
  312.         internal Type FieldType {
  313.             get { return fieldType; }
  314.         }
  315.        
  316.         internal TypeDesc FieldTypeDesc {
  317.             get { return fieldTypeDesc; }
  318.         }
  319.        
  320.         internal bool CheckShouldPersist {
  321.             get { return checkShouldPersist; }
  322.         }
  323.        
  324.         internal bool CheckSpecified {
  325.             get { return checkSpecified; }
  326.         }
  327.        
  328.         internal bool ReadOnly {
  329.             get { return readOnly; }
  330.         }
  331.        
  332.         internal bool IsProperty {
  333.             get { return isProperty; }
  334.         }
  335.     }
  336.    
  337.     internal class ConstantModel
  338.     {
  339.         FieldInfo fieldInfo;
  340.         long value;
  341.        
  342.         internal ConstantModel(FieldInfo fieldInfo, long value)
  343.         {
  344.             this.fieldInfo = fieldInfo;
  345.             this.value = value;
  346.         }
  347.        
  348.         internal string Name {
  349.             get { return fieldInfo.Name; }
  350.         }
  351.        
  352.         internal long Value {
  353.             get { return value; }
  354.         }
  355.        
  356.         internal FieldInfo FieldInfo {
  357.             get { return fieldInfo; }
  358.         }
  359.     }
  360.    
  361.     internal class EnumModel : TypeModel
  362.     {
  363.         ConstantModel[] constants;
  364.        
  365.         internal EnumModel(Type type, TypeDesc typeDesc, ModelScope scope) : base(type, typeDesc, scope)
  366.         {
  367.         }
  368.        
  369.         internal ConstantModel[] Constants {
  370.             get {
  371.                 if (constants == null) {
  372.                     ArrayList list = new ArrayList();
  373.                     FieldInfo[] fields = Type.GetFields();
  374.                     for (int i = 0; i < fields.Length; i++) {
  375.                         FieldInfo field = fields[i];
  376.                         ConstantModel constant = GetConstantModel(field);
  377.                         if (constant != null)
  378.                             list.Add(constant);
  379.                     }
  380.                     constants = (ConstantModel[])list.ToArray(typeof(ConstantModel));
  381.                 }
  382.                 return constants;
  383.             }
  384.         }
  385.        
  386.        
  387.         ConstantModel GetConstantModel(FieldInfo fieldInfo)
  388.         {
  389.             if (fieldInfo.IsSpecialName)
  390.                 return null;
  391.             return new ConstantModel(fieldInfo, ((IConvertible)fieldInfo.GetValue(null)).ToInt64(null));
  392.         }
  393.     }
  394. }

Developer Fusion