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.
32 using System.Collections.Generic;
33 using System.ComponentModel;
34 using System.Reflection;
36 namespace System.ComponentModel.DataAnnotations
38 class AssociatedMetadataTypeTypeDescriptor : CustomTypeDescriptor
41 Type associatedMetadataType;
42 bool associatedMetadataTypeChecked;
43 PropertyDescriptorCollection properties;
45 Type AssociatedMetadataType {
47 if (!associatedMetadataTypeChecked && associatedMetadataType == null)
48 associatedMetadataType = FindMetadataType ();
50 return associatedMetadataType;
54 public AssociatedMetadataTypeTypeDescriptor (ICustomTypeDescriptor parent, Type type)
55 : this (parent, type, null)
59 public AssociatedMetadataTypeTypeDescriptor (ICustomTypeDescriptor parent, Type type, Type associatedMetadataType)
63 this.associatedMetadataType = associatedMetadataType;
66 void CopyAttributes (object[] from, List <Attribute> to)
68 foreach (object o in from) {
69 Attribute a = o as Attribute;
77 public override AttributeCollection GetAttributes ()
79 var attributes = new List <Attribute> ();
80 CopyAttributes (type.GetCustomAttributes (true), attributes);
82 Type metaType = AssociatedMetadataType;
84 CopyAttributes (metaType.GetCustomAttributes (true), attributes);
86 return new AttributeCollection (attributes.ToArray ());
89 public override PropertyDescriptorCollection GetProperties ()
91 // Code partially copied from TypeDescriptor.TypeInfo.GetProperties
92 if (properties != null)
95 Dictionary <string, MemberInfo> metaMembers = null;
96 var propertiesHash = new Dictionary <string, bool> (); // name - null
97 var propertiesList = new List <AssociatedMetadataTypePropertyDescriptor> ();
98 Type currentType = type;
99 Type metaType = AssociatedMetadataType;
101 if (metaType != null) {
102 metaMembers = new Dictionary <string, MemberInfo> ();
103 MemberInfo[] members = metaType.GetMembers (BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
105 foreach (MemberInfo member in members) {
106 switch (member.MemberType) {
107 case MemberTypes.Field:
108 case MemberTypes.Property:
115 string name = member.Name;
116 if (metaMembers.ContainsKey (name))
119 metaMembers.Add (name, member);
123 // Getting properties type by type, because in the case of a property in the child type, where
124 // the "new" keyword is used and also the return type is changed Type.GetProperties returns
125 // also the parent property.
127 // Note that we also have to preserve the properties order here.
129 while (currentType != null && currentType != typeof (object)) {
130 PropertyInfo[] props = currentType.GetProperties (BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
131 foreach (PropertyInfo property in props) {
132 string propName = property.Name;
134 if (property.GetIndexParameters ().Length == 0 && property.CanRead && !propertiesHash.ContainsKey (propName)) {
135 MemberInfo metaMember;
137 if (metaMembers != null)
138 metaMembers.TryGetValue (propName, out metaMember);
141 propertiesList.Add (new AssociatedMetadataTypePropertyDescriptor (property, metaMember));
142 propertiesHash.Add (propName, true);
145 currentType = currentType.BaseType;
148 properties = new PropertyDescriptorCollection ((PropertyDescriptor[]) propertiesList.ToArray (), true);
152 Type FindMetadataType ()
154 associatedMetadataTypeChecked = true;
158 object[] attrs = type.GetCustomAttributes (typeof (MetadataTypeAttribute), true);
159 if (attrs == null || attrs.Length == 0)
162 var attr = attrs [0] as MetadataTypeAttribute;
166 return attr.MetadataClassType;