public void RegisterProperty(Type targetType, ItemProperty property)
        {
            if (!typeof(IExtendedDataItem).IsAssignableFrom (targetType))
                throw new InvalidOperationException ("The type '" + targetType + "' does not implement the IExtendedDataItem interface and cannot be extended with new properties");

            ClassDataType ctype = (ClassDataType) GetConfigurationDataType (targetType);
            ctype.AddProperty (property);
        }
        public void AddProperty(ItemProperty prop)
        {
            if (!prop.IsNested) {
                foreach (ItemProperty p in sortedPoperties) {
                    if (p.IsNested && p.NameList[0] == prop.Name)
                        throw CreateNestedConflictException (prop, p);
                }
            } else {
                ItemProperty p = properties [prop.NameList[0]] as ItemProperty;
                if (p != null)
                    throw CreateNestedConflictException (prop, p);
            }

            prop.SetContext (Context);
            if (properties.ContainsKey (prop.Name))
                throw new InvalidOperationException ("Duplicate property '" + prop.Name + "' in class '" + ValueType);
            properties.Add (prop.Name, prop);
            sortedPoperties.Add (prop);

            if (subtypes != null && subtypes.Count > 0) {
                foreach (ClassDataType subtype in subtypes)
                    subtype.AddProperty (prop);
            }
        }
 void SetPropValue(ItemProperty prop, object obj, object value)
 {
     if (prop.Member != null)
         prop.SetValue (obj, value);
     else if (obj is IExtendedDataItem)
         ((IExtendedDataItem)obj).ExtendedProperties [prop.Name] = value;
 }
 object GetPropValue(ItemProperty prop, object obj)
 {
     if (prop.Member != null)
         return prop.GetValue (obj);
     else if (obj is IExtendedDataItem)
         return ((IExtendedDataItem)obj).ExtendedProperties [prop.Name];
     else
         return null;
 }
 Exception CreateNestedConflictException(ItemProperty p1, ItemProperty p2)
 {
     return new InvalidOperationException ("There is a conflict between the properties '" + p1.Name + "' and '" + p2.Name + "'. Nested element properties can't be mixed with normal element properties.");
 }
        protected override void Initialize()
        {
            object[] incs = ValueType.GetCustomAttributes (typeof (DataIncludeAttribute), true);
            foreach (DataIncludeAttribute incat in incs) {
                Context.IncludeType (incat.Type);
            }

            if (ValueType.BaseType != null) {
                ClassDataType baseType = (ClassDataType) Context.GetConfigurationDataType (ValueType.BaseType);
                baseType.AddSubtype (this);
                int n=0;
                foreach (ItemProperty prop in baseType.Properties) {
                    properties.Add (prop.Name, prop);
                    sortedPoperties.Insert (n++, prop);
                }
            }

            foreach (Type interf in ValueType.GetInterfaces ()) {
                ClassDataType baseType = (ClassDataType) Context.GetConfigurationDataType (interf);
                baseType.AddSubtype (this);
            }

            MemberInfo[] members = ValueType.GetMembers (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
            foreach (MemberInfo member in members) {
                if ((member is FieldInfo || member is PropertyInfo) && member.DeclaringType == ValueType) {
                    object[] ats = member.GetCustomAttributes (true);

                    ItemPropertyAttribute at = FindPropertyAttribute (ats, 0);
                    if (at == null) continue;

                    ItemProperty prop = new ItemProperty ();
                    prop.Name = (at.Name != null) ? at.Name : member.Name;
                    prop.ExpandedCollection = member.IsDefined (typeof(ExpandedCollectionAttribute), true);
                    prop.DefaultValue = at.DefaultValue;
                    Type memberType = member is FieldInfo ? ((FieldInfo)member).FieldType : ((PropertyInfo)member).PropertyType;

                    if (prop.ExpandedCollection) {
                        ICollectionHandler handler = Context.GetCollectionHandler (memberType);
                        if (handler == null)
                            throw new InvalidOperationException ("ExpandedCollectionAttribute can't be applied to property '" + prop.Name + "' in type '" + ValueType + "' becuase it is not a valid collection.");

                        memberType = handler.GetItemType ();
                        prop.ExpandedCollectionHandler = handler;
                    }

                    if (at.ValueType != null)
                        prop.PropertyType = at.ValueType;
                    else
                        prop.PropertyType = memberType;

                    if (at.SerializationDataType != null) {
                        try {
                            prop.DataType = (DataType) Activator.CreateInstance (at.SerializationDataType, new object[] { prop.PropertyType } );
                        } catch (MissingMethodException ex) {
                            throw new InvalidOperationException ("Constructor not found for custom data type: " + at.SerializationDataType.Name + " (Type propertyType);", ex);
                        }
                    }

                    prop.Member = member;
                    AddProperty (prop);
                    prop.Initialize (ats, 0);

                    if (prop.ExpandedCollection && prop.DataType.IsSimpleType)
                        throw new InvalidOperationException ("ExpandedCollectionAttribute is not allowed in collections of simple types");
                }
            }
        }