private static void SetupImport() { BuildingInformation = new BuildingInformationCollection(); /* This is where behavior for each .grid-attribute is being inserted into the dictionary. */ if (!AttributeMethods.ContainsKey(ParentTypes.Person)) { AttributeMethods.Add(ParentTypes.Person, Tuple.Create( new Action(delegate { Target = new PersonInformation(); TargetInformationList = typeof(PersonInformation).GetProperties().ToList(); }), new Func <string, object[]>(value => new object[] { value }), new Action(delegate { ((BuildingInformationCollection)BuildingInformation).PeopleCollection[CurrentPerson++] = (PersonInformation)Target; }))); } if (!AttributeMethods.ContainsKey(ParentTypes.Settings)) { AttributeMethods.Add(ParentTypes.Settings, Tuple.Create( new Action(delegate { Target = BuildingInformation; TargetInformationList = typeof(BuildingInformationCollection).GetProperties().ToList(); }), new Func <string, object[]>(value => new object[] { value }), new Action(delegate { }))); } if (!AttributeMethods.ContainsKey(ParentTypes.People)) { AttributeMethods.Add(ParentTypes.People, AttributeMethods[ParentTypes.Settings]); } if (!AttributeMethods.ContainsKey(ParentTypes.Floor)) { AttributeMethods.Add(ParentTypes.Floor, Tuple.Create( new Action(delegate { Target = new FloorInformation(); TargetInformationList = typeof(FloorInformation).GetProperties().ToList(); }), new Func <string, object[]>(delegate(string value) { return(value.Replace(" ", "").Split(',')); }), new Action(delegate { ((BuildingInformationCollection)BuildingInformation).FloorCollection[CurrentFloor++] = (FloorInformation)Target; }))); } }
internal static BuildingInformationCollection ImportBuilding(string filePath) { /* BuildingInformation is what we're going to return when the building has been sucessfully imported. * Because of how the import mechanisms work, BuildingInformation has to be instantiated and visible for the entire class.*/ if (BuildingInformation == null) { SetupImport(); } using (XmlReader reader = XmlReader.Create(File.OpenRead(filePath))) { while (reader.Read()) { if (reader.NodeType == XmlNodeType.Whitespace || reader.Value == "\n") { continue; } if (reader.HasAttributes) { /* A start element marks a new parent */ if (reader.IsStartElement()) { ParentTypes parentPlaceholder; NodeParent = (Enum.TryParse(reader.Name, out parentPlaceholder) ? parentPlaceholder : ParentTypes.None); /* If whatever parent read is known, run the "preperation" for that parent */ if (AttributeMethods.ContainsKey(NodeParent)) { AttributeMethods[NodeParent].Item1?.DynamicInvoke(); } else { continue; } } /* Looping through all attributes of node/element */ for (int i = 0; i < reader.AttributeCount; i++) { reader.MoveToNextAttribute(); string name = reader.Name, value = reader.Value; var currentMemberInfo = TargetInformationList.FirstOrDefault(p => p.Name == name); if (currentMemberInfo == default(PropertyInfo)) { continue; /* Like a null-reference check-up */ } /* If necessary, do some work on the value before converting it to object[] for later use */ object[] values = AttributeMethods[NodeParent].Item2?.DynamicInvoke(value) as object[]; if (values == null) { continue; } /* Loop through values, setting the value to the correct property in the target class/struct. * Type conversion is handled through AttributeConversion: * - As stated previously, AttributeConverter is a generic method, for which types are not known at compile time. * To get around this, an instance of the method is created, in which the type is provided. * The return value from the method is the value for the set-method of the property, for which we are trying to assign a value. */ foreach (string item in values) { currentMemberInfo.SetValue(Target, AttributeConversion.MakeGenericMethod(currentMemberInfo.PropertyType).Invoke(null, new object[] { item })); } } AttributeMethods[NodeParent].Item3?.DynamicInvoke(); } } ; } /* We're finished, return the results for further working */ return((BuildingInformationCollection)BuildingInformation); }