2 // AssociatedMetadataTypeTypeDescriptionProvider.cs
5 // Marek Habersack <mhabersack@novell.com>
7 // Copyright (C) 2009 Novell Inc. http://novell.com
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections.Generic;
32 using System.ComponentModel;
33 using System.Reflection;
35 namespace System.ComponentModel.DataAnnotations
37 class AssociatedMetadataTypeTypeDescriptor : CustomTypeDescriptor
40 Type associatedMetadataType;
41 bool associatedMetadataTypeChecked;
42 PropertyDescriptorCollection properties;
44 Type AssociatedMetadataType {
46 if (!associatedMetadataTypeChecked && associatedMetadataType == null)
47 associatedMetadataType = FindMetadataType ();
49 return associatedMetadataType;
53 public AssociatedMetadataTypeTypeDescriptor (ICustomTypeDescriptor parent, Type type)
54 : this (parent, type, null)
58 public AssociatedMetadataTypeTypeDescriptor (ICustomTypeDescriptor parent, Type type, Type associatedMetadataType)
62 this.associatedMetadataType = associatedMetadataType;
65 void CopyAttributes (object[] from, List <Attribute> to)
67 foreach (object o in from) {
68 Attribute a = o as Attribute;
76 public override AttributeCollection GetAttributes ()
78 var attributes = new List <Attribute> ();
79 CopyAttributes (type.GetCustomAttributes (true), attributes);
81 Type metaType = AssociatedMetadataType;
83 CopyAttributes (metaType.GetCustomAttributes (true), attributes);
85 return new AttributeCollection (attributes.ToArray ());
88 public override PropertyDescriptorCollection GetProperties ()
90 // Code partially copied from TypeDescriptor.TypeInfo.GetProperties
91 if (properties != null)
94 Dictionary <string, MemberInfo> metaMembers = null;
95 var propertiesHash = new Dictionary <string, bool> (); // name - null
96 var propertiesList = new List <AssociatedMetadataTypePropertyDescriptor> ();
97 Type currentType = type;
98 Type metaType = AssociatedMetadataType;
100 if (metaType != null) {
101 metaMembers = new Dictionary <string, MemberInfo> ();
102 MemberInfo[] members = metaType.GetMembers (BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
104 foreach (MemberInfo member in members) {
105 switch (member.MemberType) {
106 case MemberTypes.Field:
107 case MemberTypes.Property:
114 string name = member.Name;
115 if (metaMembers.ContainsKey (name))
118 metaMembers.Add (name, member);
122 // Getting properties type by type, because in the case of a property in the child type, where
123 // the "new" keyword is used and also the return type is changed Type.GetProperties returns
124 // also the parent property.
126 // Note that we also have to preserve the properties order here.
128 while (currentType != null && currentType != typeof (object)) {
129 PropertyInfo[] props = currentType.GetProperties (BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
130 foreach (PropertyInfo property in props) {
131 string propName = property.Name;
133 if (property.GetIndexParameters ().Length == 0 && property.CanRead && !propertiesHash.ContainsKey (propName)) {
134 MemberInfo metaMember;
136 if (metaMembers != null)
137 metaMembers.TryGetValue (propName, out metaMember);
140 propertiesList.Add (new AssociatedMetadataTypePropertyDescriptor (property, metaMember));
141 propertiesHash.Add (propName, true);
144 currentType = currentType.BaseType;
147 properties = new PropertyDescriptorCollection ((PropertyDescriptor[]) propertiesList.ToArray (), true);
151 Type FindMetadataType ()
153 associatedMetadataTypeChecked = true;
157 object[] attrs = type.GetCustomAttributes (typeof (MetadataTypeAttribute), true);
158 if (attrs == null || attrs.Length == 0)
161 var attr = attrs [0] as MetadataTypeAttribute;
165 return attr.MetadataClassType;