/// <summary> /// Initializes a new instance of the <see cref="FileHierarchyReflector"/> class. /// </summary> /// <param name="index">The <see cref="Index"/>.</param> /// <param name="fh">The <see cref="FileHierarchy"/>.</param> /// <param name="pi">The <see cref="PropertyInfo"/>.</param> /// <param name="ff">The <see cref="FileFormat"/>.</param> internal FileHierarchyReflector(int index, FileHierarchyAttribute fh, PropertyInfo pi, FileFormatBase ff) { Index = index; Order = fh.Order < 0 ? int.MaxValue : fh.Order; FileHierarchy = fh; PropertyInfo = pi; FileFormat = ff; // Where an intrinsic type then we have an issue. if (FileColumnReflector.GetTypeCode(PropertyInfo.PropertyType) != TypeCode.Object) { throw new ArgumentException($"Type '{PropertyInfo.DeclaringType.Name}' Property '{PropertyInfo.Name}' must be a class or collection (FileHierarchyAttribute).", nameof(pi)); } // Determine the collection type. _collTypeReflector = ComplexTypeReflector.Create(PropertyInfo); // Load/cache the corresponding property type. var frr = (_collTypeReflector.ComplexTypeCode == ComplexTypeCode.Object) ? FileFormat.GetFileRecordReflector(PropertyInfo.PropertyType) : FileFormat.GetFileRecordReflector(_collTypeReflector.ItemType); if (fh.ValidationType != null) { frr.SetValidatorType(fh.ValidationType); } }
/// <summary> /// Initializes a new instance of the <see cref="FileColumnReflector"/> class. /// </summary> /// <param name="index">The <see cref="Index"/>.</param> /// <param name="fc">The <see cref="FileColumn"/>.</param> /// <param name="pi">The <see cref="PropertyInfo"/>.</param> /// <param name="ff">The <see cref="FileFormat"/>.</param> internal FileColumnReflector(int index, FileColumnAttribute fc, PropertyInfo pi, FileFormatBase ff) { Index = index; Order = fc.Order < 0 ? int.MaxValue : fc.Order; Name = string.IsNullOrEmpty(fc.Name) ? pi.Name : fc.Name; FileColumn = fc; PropertyInfo = pi; FileFormat = ff; // Get the property type being mindful of nullables. if (PropertyInfo.PropertyType.GetTypeInfo().IsGenericType&& PropertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable <>)) { PropertyTypeCode = GetTypeCode(PropertyInfo.PropertyType.GetGenericArguments()[0]); PropertyIsNullable = true; } else { PropertyTypeCode = GetTypeCode(PropertyInfo.PropertyType); } _valueConverter = FileFormat.Converters.Get(PropertyInfo.PropertyType, FileColumn.TextValueConverterKey, FileColumn.TextValueConverterType); if (!string.IsNullOrEmpty(FileColumn.TextValueConverterKey) && _valueConverter == null) { throw new InvalidOperationException(string.Format("FileColumnAttribute has TextValueConverterKey of '{0}' is not found within the FileFormat.Converters.", FileColumn.TextValueConverterKey)); } if (FileColumn.IsLineNumber && PropertyTypeCode != TypeCode.Int32 && PropertyTypeCode != TypeCode.Int64) { throw new InvalidOperationException("FileColumnAttribute has IsLineNumber set to true; the underlying property type must be either Int32 or Int64."); } }
/// <summary> /// Gets the underlying hierarchy for the specified <see cref="FileFormatBase"/>. /// </summary> /// <param name="fileFormat">The <see cref="FileFormatBase"/>.</param> /// <returns>A dictionary containing the full hierarchy.</returns> public static Dictionary <string, FileRecordHierarchyItem> GetHierarchy(FileFormatBase fileFormat) { var dict = new Dictionary <string, FileRecordHierarchyItem>(); Get(fileFormat, dict, new FileRecordHierarchyItem { RecordIdentifier = fileFormat.ContentRecordIdentifier, Level = 0, Parent = null, RecordReflector = fileFormat.GetFileRecordReflector(fileFormat.ContentRowType) }, null); return(dict); }
/// <summary> /// Initializes a new instance of the <see cref="FileColumnReflector"/> class. /// </summary> internal FileRecordReflector(Type type, FileFormatBase ff) { Type = type; TypeInfo = type.GetTypeInfo(); if (!TypeInfo.IsClass) { throw new ArgumentException($"Type '{type.Name}' must be a class.", nameof(type)); } // Get all the property/column metadata. FileFormat = ff; int i = 0; var columns = new List <FileColumnReflector>(); var children = new List <FileHierarchyReflector>(); foreach (var pi in TypeReflector.GetProperties(Type)) { i++; var fca = pi.GetCustomAttribute <FileColumnAttribute>(); var fha = pi.GetCustomAttribute <FileHierarchyAttribute>(); if (fca != null && fha != null) { throw new InvalidOperationException($"Type '{type.Name}' property '{pi.Name}' cannot specify both a FileColumnAttribute and FileHierarchyAttribute."); } if (fca != null) { columns.Add(new FileColumnReflector(i, fca, pi, FileFormat)); } if (fha != null) { var fhr = new FileHierarchyReflector(i, fha, pi, ff); if (children.SingleOrDefault(x => x.RecordIdentifier == fhr.RecordIdentifier) != null) { throw new InvalidOperationException($"Type '{type.Name}' property '{pi.Name}' FileHierarchyAttribute has a duplicate Record Identifier '{fhr.RecordIdentifier}' (must be unique within Type)."); } children.Add(new FileHierarchyReflector(i, fha, pi, ff)); } } // Order the Columns and Children by Order and Index for usage. Columns = columns.OrderBy(x => x.Order).ThenBy(x => x.Index).ToList(); Children = children.OrderBy(x => x.Order).ThenBy(x => x.Index).ToList(); for (int j = 0; j < Children.Count; j++) { _childrenIndexes.Add(Children[j].RecordIdentifier, j); } }
/// <summary> /// Gets the underlying hierarchy for an item. /// </summary> private static void Get(FileFormatBase fileFormat, Dictionary <string, FileRecordHierarchyItem> dict, FileRecordHierarchyItem item, PropertyInfo pi) { if (dict.ContainsKey(item.RecordIdentifier)) { throw new InvalidOperationException(string.Format("Type '{0}' property '{1}' FileHierarchyAttribute has a duplicate Record Identifier '{2}'; must be unique within hierarchy).", pi.DeclaringType.Name, pi.Name, item.RecordIdentifier)); } if (fileFormat.HeaderRecordIdentifier != null && item.RecordIdentifier == fileFormat.HeaderRecordIdentifier) { throw new InvalidOperationException(string.Format("Type '{0}' property '{1}' FileHierarchyAttribute has a duplicate Record Identifier '{2}'; must be different to the Header Record Identifier).", pi.DeclaringType.Name, pi.Name, item.RecordIdentifier)); } if (fileFormat.TrailerRecordIdentifier != null && item.RecordIdentifier == fileFormat.TrailerRecordIdentifier) { throw new InvalidOperationException(string.Format("Type '{0}' property '{1}' FileHierarchyAttribute has a duplicate Record Identifier '{2}'; must be different to the Trailer Record Identifier).", pi.DeclaringType.Name, pi.Name, item.RecordIdentifier)); } dict.Add(item.RecordIdentifier, item); if (item.RecordReflector.Children == null || item.RecordReflector.Children.Length == 0) { return; } foreach (var fhr in item.RecordReflector.Children) { var frhh = new FileRecordHierarchyItem { RecordIdentifier = fhr.RecordIdentifier, Level = item.Level + 1, Parent = item, RecordReflector = fileFormat.GetFileRecordReflector(fhr.PropertyType), HierarchyReflector = fhr }; Get(fileFormat, dict, frhh, fhr.PropertyInfo); item.Children.Add(frhh.RecordIdentifier, frhh); } }