/// <summary> /// Reads a property value from the given <see cref="BinaryReader"/>. /// </summary> /// <param name="reader">The reader, containing the data.</param> /// <param name="recordInfo">The reflected field information.</param> /// <param name="property">The property which will contain the data.</param> /// <param name="elementType">The element type of the field. This is primarily used for reading arrays.</param> /// <param name="version">The version of the record.</param> /// <returns>The value that should be assigned to the property.</returns> public static object ReadPropertyValue ( BinaryReader reader, RecordFieldInformation recordInfo, PropertyInfo property, Type elementType, WarcraftVersion version ) { object fieldValue; if (DBCInspector.IsPropertyForeignKey(property)) { // Get the foreign key information var foreignKeyAttribute = recordInfo.PropertyForeignKeyAttributes[property]; // Get the inner type var keyType = GetUnderlyingStoredPrimitiveType(elementType); var keyValue = reader.Read(keyType); // Create the specific ForeignKey type var genericKeyFieldType = typeof(ForeignKey <>); var specificKeyFieldType = genericKeyFieldType.MakeGenericType(keyType); fieldValue = Activator.CreateInstance ( specificKeyFieldType, foreignKeyAttribute.Database, foreignKeyAttribute.Field, keyValue ); } else if (elementType.IsEnum) { // Get the underlying type of the enum var enumType = elementType.GetEnumUnderlyingType(); fieldValue = reader.Read(enumType); } else { if (elementType == typeof(LocalizedStringReference)) { fieldValue = reader.Read(elementType, version); } else { fieldValue = reader.Read(elementType); } } return(fieldValue); }
/// <summary> /// Initializes a new instance of the <see cref="RecordFieldInformation"/> class. /// </summary> /// <param name="recordType">The type of record to build the reflection data for.</param> /// <param name="version">The version to build data for.</param> /// <exception cref="ArgumentException">Thrown if the specified type is not a record type.</exception> public RecordFieldInformation(Type recordType, WarcraftVersion version) { if (!recordType.IsSubclassOf(typeof(DBCRecord))) { throw new ArgumentException("The specified type was not a record type.", nameof(recordType)); } if (!recordType.GetCustomAttributes().Any(a => a is DatabaseRecordAttribute)) { throw new ArgumentException($"The record type {recordType.Name} was not decorated with the \"DatabaseRecord\" attribute."); } this.Type = recordType; this.Version = version; var orderer = new FieldOrderer(this.Version, DBCInspector.GetVersionRelevantProperties(this.Version, this.Type).ToList()); this.VersionRelevantProperties = orderer.ReorderProperties().ToList(); this.PropertyFieldAttributes = new Dictionary <PropertyInfo, RecordFieldAttribute>(); this.PropertyFieldArrayAttributes = new Dictionary <PropertyInfo, RecordFieldArrayAttribute>(); this.PropertyFieldArrayElementTypes = new Dictionary <PropertyInfo, Type>(); this.PropertyForeignKeyAttributes = new Dictionary <PropertyInfo, ForeignKeyInfoAttribute>(); foreach (var property in this.VersionRelevantProperties) { if (!property.CanWrite) { throw new ArgumentException("Property setter not found. Record properties must have a setter."); } var fieldInfoAttribute = DBCInspector.GetPropertyFieldAttribute(property); this.PropertyFieldAttributes.Add(property, fieldInfoAttribute); if (DBCInspector.IsPropertyFieldArray(property)) { this.PropertyFieldArrayAttributes.Add(property, DBCInspector.GetVersionRelevantPropertyFieldArrayAttribute(this.Version, property)); this.PropertyFieldArrayElementTypes.Add(property, DBCInspector.GetFieldArrayPropertyElementType(property.PropertyType)); } if (DBCInspector.IsPropertyForeignKey(property)) { this.PropertyForeignKeyAttributes.Add(property, DBCInspector.GetForeignKeyInfo(property)); } } this.FieldCount = DBCInspector.GetPropertyCount(this.Version, this.Type); this.Size = DBCInspector.GetRecordSize(this.Version, this.Type); }