Models.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. //------------------------------------------------------------------------------
  2. // <copyright file="Models.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // <owner current="true" primary="true">Microsoft</owner>
  6. //------------------------------------------------------------------------------
  7. namespace System.Xml.Serialization {
  8. using System;
  9. using System.Reflection;
  10. using System.Collections;
  11. using System.Diagnostics;
  12. // These classes define the abstract serialization model, e.g. the rules for WHAT is serialized.
  13. // The answer of HOW the values are serialized is answered by a particular reflection importer
  14. // by looking for a particular set of custom attributes specific to the serialization format
  15. // and building an appropriate set of accessors/mappings.
  16. internal class ModelScope {
  17. TypeScope typeScope;
  18. Hashtable models = new Hashtable();
  19. Hashtable arrayModels = new Hashtable();
  20. internal ModelScope(TypeScope typeScope) {
  21. this.typeScope = typeScope;
  22. }
  23. internal TypeScope TypeScope {
  24. get { return typeScope; }
  25. }
  26. internal TypeModel GetTypeModel(Type type) {
  27. return GetTypeModel(type, true);
  28. }
  29. internal TypeModel GetTypeModel(Type type, bool directReference) {
  30. TypeModel model = (TypeModel)models[type];
  31. if (model != null) return model;
  32. TypeDesc typeDesc = typeScope.GetTypeDesc(type, null, directReference);
  33. switch (typeDesc.Kind) {
  34. case TypeKind.Enum:
  35. model = new EnumModel(type, typeDesc, this);
  36. break;
  37. case TypeKind.Primitive:
  38. model = new PrimitiveModel(type, typeDesc, this);
  39. break;
  40. case TypeKind.Array:
  41. case TypeKind.Collection:
  42. case TypeKind.Enumerable:
  43. model = new ArrayModel(type, typeDesc, this);
  44. break;
  45. case TypeKind.Root:
  46. case TypeKind.Class:
  47. case TypeKind.Struct:
  48. model = new StructModel(type, typeDesc, this);
  49. break;
  50. default:
  51. if (!typeDesc.IsSpecial) throw new NotSupportedException(Res.GetString(Res.XmlUnsupportedTypeKind, type.FullName));
  52. model = new SpecialModel(type, typeDesc, this);
  53. break;
  54. }
  55. models.Add(type, model);
  56. return model;
  57. }
  58. internal ArrayModel GetArrayModel(Type type) {
  59. TypeModel model = (TypeModel)arrayModels[type];
  60. if (model == null) {
  61. model = GetTypeModel(type);
  62. if (!(model is ArrayModel)) {
  63. TypeDesc typeDesc = typeScope.GetArrayTypeDesc(type);
  64. model = new ArrayModel(type, typeDesc, this);
  65. }
  66. arrayModels.Add(type, model);
  67. }
  68. return (ArrayModel)model;
  69. }
  70. }
  71. internal abstract class TypeModel {
  72. TypeDesc typeDesc;
  73. Type type;
  74. ModelScope scope;
  75. protected TypeModel(Type type, TypeDesc typeDesc, ModelScope scope) {
  76. this.scope = scope;
  77. this.type = type;
  78. this.typeDesc = typeDesc;
  79. }
  80. internal Type Type {
  81. get { return type; }
  82. }
  83. internal ModelScope ModelScope {
  84. get { return scope; }
  85. }
  86. internal TypeDesc TypeDesc {
  87. get { return typeDesc; }
  88. }
  89. }
  90. internal class ArrayModel : TypeModel {
  91. internal ArrayModel(Type type, TypeDesc typeDesc, ModelScope scope) : base(type, typeDesc, scope) { }
  92. internal TypeModel Element {
  93. get { return ModelScope.GetTypeModel(TypeScope.GetArrayElementType(Type, null)); }
  94. }
  95. }
  96. internal class PrimitiveModel : TypeModel {
  97. internal PrimitiveModel(Type type, TypeDesc typeDesc, ModelScope scope) : base(type, typeDesc, scope) { }
  98. }
  99. internal class SpecialModel : TypeModel {
  100. internal SpecialModel(Type type, TypeDesc typeDesc, ModelScope scope) : base(type, typeDesc, scope) { }
  101. }
  102. internal class StructModel : TypeModel {
  103. internal StructModel(Type type, TypeDesc typeDesc, ModelScope scope) : base(type, typeDesc, scope) { }
  104. internal MemberInfo[] GetMemberInfos() {
  105. // we use to return Type.GetMembers() here, the members were returned in a different order: fields first, properties last
  106. // Current System.Reflection code returns members in oposite order: properties first, then fields.
  107. // This code make sure that returns members in the Everett order.
  108. MemberInfo[] members = Type.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
  109. MemberInfo[] fieldsAndProps = new MemberInfo[members.Length];
  110. int cMember = 0;
  111. // first copy all non-property members over
  112. for (int i = 0; i < members.Length; i++) {
  113. if ((members[i].MemberType & MemberTypes.Property) == 0) {
  114. fieldsAndProps[cMember++] = members[i];
  115. }
  116. }
  117. // now copy all property members over
  118. for (int i = 0; i < members.Length; i++) {
  119. if ((members[i].MemberType & MemberTypes.Property) != 0) {
  120. fieldsAndProps[cMember++] = members[i];
  121. }
  122. }
  123. return fieldsAndProps;
  124. }
  125. internal FieldModel GetFieldModel(MemberInfo memberInfo) {
  126. FieldModel model = null;
  127. if (memberInfo is FieldInfo)
  128. model = GetFieldModel((FieldInfo)memberInfo);
  129. else if (memberInfo is PropertyInfo)
  130. model = GetPropertyModel((PropertyInfo)memberInfo);
  131. if (model != null) {
  132. if (model.ReadOnly && model.FieldTypeDesc.Kind != TypeKind.Collection && model.FieldTypeDesc.Kind != TypeKind.Enumerable)
  133. return null;
  134. }
  135. return model;
  136. }
  137. void CheckSupportedMember(TypeDesc typeDesc, MemberInfo member, Type type) {
  138. if (typeDesc == null)
  139. return;
  140. if (typeDesc.IsUnsupported) {
  141. if (typeDesc.Exception == null) {
  142. typeDesc.Exception = new NotSupportedException(Res.GetString(Res.XmlSerializerUnsupportedType, typeDesc.FullName));
  143. }
  144. throw new InvalidOperationException(Res.GetString(Res.XmlSerializerUnsupportedMember, member.DeclaringType.FullName + "." + member.Name, type.FullName), typeDesc.Exception);
  145. }
  146. CheckSupportedMember(typeDesc.BaseTypeDesc, member, type);
  147. CheckSupportedMember(typeDesc.ArrayElementTypeDesc, member, type);
  148. }
  149. FieldModel GetFieldModel(FieldInfo fieldInfo) {
  150. if (fieldInfo.IsStatic) return null;
  151. if (fieldInfo.DeclaringType != Type) return null;
  152. TypeDesc typeDesc = ModelScope.TypeScope.GetTypeDesc(fieldInfo.FieldType, fieldInfo, true, false);
  153. if (fieldInfo.IsInitOnly && typeDesc.Kind != TypeKind.Collection && typeDesc.Kind != TypeKind.Enumerable)
  154. return null;
  155. CheckSupportedMember(typeDesc, fieldInfo, fieldInfo.FieldType);
  156. return new FieldModel(fieldInfo, fieldInfo.FieldType, typeDesc);
  157. }
  158. FieldModel GetPropertyModel(PropertyInfo propertyInfo) {
  159. if (propertyInfo.DeclaringType != Type) return null;
  160. if (CheckPropertyRead(propertyInfo)) {
  161. TypeDesc typeDesc = ModelScope.TypeScope.GetTypeDesc(propertyInfo.PropertyType, propertyInfo, true, false);
  162. // Fix for CSDMain 100492, please contact arssrvlt if you need to change this line
  163. if (!propertyInfo.CanWrite && typeDesc.Kind != TypeKind.Collection && typeDesc.Kind != TypeKind.Enumerable)
  164. return null;
  165. CheckSupportedMember(typeDesc, propertyInfo, propertyInfo.PropertyType);
  166. return new FieldModel(propertyInfo, propertyInfo.PropertyType, typeDesc);
  167. }
  168. return null;
  169. }
  170. //CheckProperty
  171. internal static bool CheckPropertyRead(PropertyInfo propertyInfo) {
  172. if (!propertyInfo.CanRead) return false;
  173. MethodInfo getMethod = propertyInfo.GetGetMethod();
  174. if (getMethod.IsStatic) return false;
  175. ParameterInfo[] parameters = getMethod.GetParameters();
  176. if (parameters.Length > 0) return false;
  177. return true;
  178. }
  179. }
  180. internal enum SpecifiedAccessor {
  181. None,
  182. ReadOnly,
  183. ReadWrite,
  184. }
  185. internal class FieldModel {
  186. SpecifiedAccessor checkSpecified = SpecifiedAccessor.None;
  187. MemberInfo memberInfo;
  188. MemberInfo checkSpecifiedMemberInfo;
  189. MethodInfo checkShouldPersistMethodInfo;
  190. bool checkShouldPersist;
  191. bool readOnly = false;
  192. bool isProperty = false;
  193. Type fieldType;
  194. string name;
  195. TypeDesc fieldTypeDesc;
  196. internal FieldModel(string name, Type fieldType, TypeDesc fieldTypeDesc, bool checkSpecified, bool checkShouldPersist) :
  197. this(name, fieldType, fieldTypeDesc, checkSpecified, checkShouldPersist, false) {
  198. }
  199. internal FieldModel(string name, Type fieldType, TypeDesc fieldTypeDesc, bool checkSpecified, bool checkShouldPersist, bool readOnly) {
  200. this.fieldTypeDesc = fieldTypeDesc;
  201. this.name = name;
  202. this.fieldType = fieldType;
  203. this.checkSpecified = checkSpecified ? SpecifiedAccessor.ReadWrite : SpecifiedAccessor.None;
  204. this.checkShouldPersist = checkShouldPersist;
  205. this.readOnly = readOnly;
  206. }
  207. internal FieldModel(MemberInfo memberInfo, Type fieldType, TypeDesc fieldTypeDesc) {
  208. this.name = memberInfo.Name;
  209. this.fieldType = fieldType;
  210. this.fieldTypeDesc = fieldTypeDesc;
  211. this.memberInfo = memberInfo;
  212. this.checkShouldPersistMethodInfo = memberInfo.DeclaringType.GetMethod("ShouldSerialize" + memberInfo.Name, new Type[0]);
  213. this.checkShouldPersist = this.checkShouldPersistMethodInfo != null;
  214. FieldInfo specifiedField = memberInfo.DeclaringType.GetField(memberInfo.Name + "Specified");
  215. if (specifiedField != null) {
  216. if (specifiedField.FieldType != typeof(bool)) {
  217. throw new InvalidOperationException(Res.GetString(Res.XmlInvalidSpecifiedType, specifiedField.Name, specifiedField.FieldType.FullName, typeof(bool).FullName));
  218. }
  219. this.checkSpecified = specifiedField.IsInitOnly ? SpecifiedAccessor.ReadOnly : SpecifiedAccessor.ReadWrite;
  220. this.checkSpecifiedMemberInfo = specifiedField;
  221. }
  222. else {
  223. PropertyInfo specifiedProperty = memberInfo.DeclaringType.GetProperty(memberInfo.Name + "Specified");
  224. if (specifiedProperty != null) {
  225. if (StructModel.CheckPropertyRead(specifiedProperty)) {
  226. this.checkSpecified = specifiedProperty.CanWrite ? SpecifiedAccessor.ReadWrite : SpecifiedAccessor.ReadOnly;
  227. this.checkSpecifiedMemberInfo = specifiedProperty;
  228. }
  229. if (this.checkSpecified != SpecifiedAccessor.None && specifiedProperty.PropertyType != typeof(bool)) {
  230. throw new InvalidOperationException(Res.GetString(Res.XmlInvalidSpecifiedType, specifiedProperty.Name, specifiedProperty.PropertyType.FullName, typeof(bool).FullName));
  231. }
  232. }
  233. }
  234. if (memberInfo is PropertyInfo) {
  235. readOnly = !((PropertyInfo)memberInfo).CanWrite;
  236. isProperty = true;
  237. }
  238. else if (memberInfo is FieldInfo) {
  239. readOnly = ((FieldInfo)memberInfo).IsInitOnly;
  240. }
  241. }
  242. internal string Name {
  243. get { return name; }
  244. }
  245. internal Type FieldType {
  246. get { return fieldType; }
  247. }
  248. internal TypeDesc FieldTypeDesc {
  249. get { return fieldTypeDesc; }
  250. }
  251. internal bool CheckShouldPersist {
  252. get { return checkShouldPersist; }
  253. }
  254. internal SpecifiedAccessor CheckSpecified {
  255. get { return checkSpecified; }
  256. }
  257. internal MemberInfo MemberInfo {
  258. get { return memberInfo; }
  259. }
  260. internal MemberInfo CheckSpecifiedMemberInfo {
  261. get { return checkSpecifiedMemberInfo; }
  262. }
  263. internal MethodInfo CheckShouldPersistMethodInfo {
  264. get { return checkShouldPersistMethodInfo; }
  265. }
  266. internal bool ReadOnly {
  267. get { return readOnly; }
  268. }
  269. internal bool IsProperty {
  270. get { return isProperty; }
  271. }
  272. }
  273. internal class ConstantModel {
  274. FieldInfo fieldInfo;
  275. long value;
  276. internal ConstantModel(FieldInfo fieldInfo, long value) {
  277. this.fieldInfo = fieldInfo;
  278. this.value = value;
  279. }
  280. internal string Name {
  281. get { return fieldInfo.Name; }
  282. }
  283. internal long Value {
  284. get { return value; }
  285. }
  286. internal FieldInfo FieldInfo {
  287. get { return fieldInfo; }
  288. }
  289. }
  290. internal class EnumModel : TypeModel {
  291. ConstantModel[] constants;
  292. internal EnumModel(Type type, TypeDesc typeDesc, ModelScope scope) : base(type, typeDesc, scope) { }
  293. internal ConstantModel[] Constants {
  294. get {
  295. if (constants == null) {
  296. ArrayList list = new ArrayList();
  297. FieldInfo[] fields = Type.GetFields();
  298. for (int i = 0; i < fields.Length; i++) {
  299. FieldInfo field = fields[i];
  300. ConstantModel constant = GetConstantModel(field);
  301. if (constant != null) list.Add(constant);
  302. }
  303. constants = (ConstantModel[])list.ToArray(typeof(ConstantModel));
  304. }
  305. return constants;
  306. }
  307. }
  308. ConstantModel GetConstantModel(FieldInfo fieldInfo) {
  309. if (fieldInfo.IsSpecialName) return null;
  310. return new ConstantModel(fieldInfo, ((IConvertible)fieldInfo.GetValue(null)).ToInt64(null));
  311. }
  312. }
  313. }