/// <inheritdoc /> /// <remarks>The function uses Convert class functionality to convert from XmlValue of child nodes into the target type.</remarks> public object ProcessElements(XmlElement _parent_element, Type _target_type, X2OConfig _config) { if (!_target_type.IsValueType && !_target_type.Equals(typeof(string))) { return(null); } var xval = _parent_element.ChildNodes[0].Value; var tgt_type_val = Convert.ChangeType(xval, _target_type); return(tgt_type_val); }
/// <inheritdoc /> /// <remarks> /// The function looks for the fromFile attribute, and if found, and there are no children it uses the X2OReader to /// read this file and desrialize its content, which is then returned as the value of this element. /// </remarks> public object ProcessElements(XmlElement _parent_element, Type _target_type, X2OConfig _config) { var external_config_attr = _parent_element.Attributes["fromFile"]; if (external_config_attr != null && !_parent_element.HasChildNodes) { foreach (var possible_file in FindExistingFiles(external_config_attr.Value, _config)) { try { var result = X2OReader.ReadFromFile(possible_file, _config); if (result != null) { return(result); } } catch { } } } return(null); }
/// <summary> /// Based on the filename in the attribute for loading the external file, it finds the files, which exists /// and could be loaded to be read. /// It uses the ExternalConfigSearchPaths property of the X2OConfig, after it is not found in the application current directory. /// </summary> private IEnumerable <string> FindExistingFiles(string _filename, X2OConfig _config) { var fi = new System.IO.FileInfo(_filename); if (fi.Exists) { yield return(fi.FullName); } if (_config?.ExternalConfigSearchPaths != null) { foreach (var search_path in _config.ExternalConfigSearchPaths) { var pathname = System.IO.Path.Combine(search_path, _filename); fi = new System.IO.FileInfo(pathname); if (fi.Exists) { yield return(fi.FullName); } } } yield break; }
/// <summary> /// This function tries to create the instance of the target type according to the information in _declared_type and _parent_element. /// In this implementation, it is able to create only the List<object> or List<T> types, according to the _declared_type and /// only in cases, that the _declared_type is convertible into these Lists. /// </summary> public virtual EnumerableInfo?CreateEnumerable(XmlElement _parent_element, Type _target_type, X2OConfig _config) { Action <IEnumerable, object> add_action = (l, i) => l.GetType().GetMethod("Add").Invoke(l, new[] { i }); // find if it is generic, find the generic type, create list of that type, and try if it can convert into declared type if (_target_type.IsGenericType && _target_type.GenericTypeArguments.Length == 1) { // it is generic type, like List<T> or IEnumerable<T> var item_type = _target_type.GenericTypeArguments[0]; var tgt_type = typeof(List <>).MakeGenericType(item_type); if (_target_type.IsAssignableFrom(tgt_type)) { try { return(new EnumerableInfo() { Enumerable = Activator.CreateInstance(tgt_type) as IEnumerable, DeclaredItemType = item_type, AddAction = add_action }); } catch { } } } else { if (_target_type.IsAssignableFrom(typeof(List <object>))) { try { return(new EnumerableInfo() { Enumerable = new List <object>(), DeclaredItemType = typeof(object), AddAction = add_action }); } catch { } } } return(null); }
/// <inheritdoc /> /// <remarks> /// This function firstly check, if the type will be IEnumerable. /// Then it tries to create the instance and get information about the enumerable by calling function CreateEnumerable. /// If successful, it goes through all the child nodes of _parent_element and deserializes the objects, which are than add /// using the AddAction. /// </remarks> public virtual object ProcessElements(XmlElement _parent_element, Type _target_type, X2OConfig _config) { // if the declared type is not the IEnumerable, we cannot help here if (!typeof(IEnumerable).IsAssignableFrom(_target_type)) { return(null); } var enumerable_info = CreateEnumerable(_parent_element, _target_type, _config); if (!enumerable_info.HasValue) { return(null); } foreach (XmlElement element in _parent_element.ChildNodes) { var item = _config.Processor.ProcessElements(element, enumerable_info.Value.DeclaredItemType, _config); enumerable_info.Value.AddAction(enumerable_info.Value.Enumerable, item); } return(enumerable_info.Value.Enumerable); }
/// <summary></summary> public virtual DictionaryInfo?CreateDictionary(XmlElement _parent_element, Type _target_type, X2OConfig _config) { if (_target_type.IsGenericType && _target_type.GenericTypeArguments.Length == 2) { // generic dictionary like Dictionary<T1, T2> var key_type = _target_type.GenericTypeArguments[0]; var value_type = _target_type.GenericTypeArguments[1]; var dict_type = typeof(Dictionary <,>).MakeGenericType(key_type, value_type); if (dict_type.IsAssignableFrom(_target_type)) { try { var dict = Activator.CreateInstance(_target_type) as IDictionary; // declared type is derived from Dictionary<T1,T2> and we guessed the type parameters correctly var dict_info = new DictionaryInfo() { Dictionary = dict, KeyType = key_type, ValueType = value_type }; return(dict_info); } catch { } } } // in any other cases, we cannot guess the key and value types without traversing the object hierarchy // for these cases, it is better to return without guessing // user can override this function to get the correct types return(null); }
/// <inheritdoc /> /// <remarks> /// </remarks> public virtual object ProcessElements(XmlElement _parent_element, Type _target_type, X2OConfig _config) { // if the declared type is not the IDictionary, we cannot help here if (!typeof(IDictionary).IsAssignableFrom(_target_type)) { return(null); } var dictionary_info = CreateDictionary(_parent_element, _target_type, _config); if (!dictionary_info.HasValue) { return(null); } foreach (XmlElement element in _parent_element.ChildNodes) { if (element.Name == "Item") { XmlElement key_node = null, value_node = null; foreach (XmlElement item_element in element.ChildNodes) { if (item_element.Name == "Key") { key_node = item_element; } if (item_element.Name == "Value") { value_node = item_element; } } if (key_node != null) { var key = _config.Processor.ProcessElements(key_node, dictionary_info.Value.KeyType, _config); object value = null; if (value_node != null) { value = _config.Processor.ProcessElements(value_node, dictionary_info.Value.ValueType, _config); } if (key != null) { dictionary_info.Value.Dictionary.Add(key, value); } } } } return(dictionary_info.Value.Dictionary); }
/// <summary> /// Based on the _declared_type and XmlElement settings of _parent_element it creates the target object, where the values from the /// child nodes are to be read. /// </summary> /// <returns>The instance of the target object or null, if the processor doesn't know how to read such type of object.</returns> public virtual object CreateInstance(XmlElement _parent_element, Type _target_type, X2OConfig _config) { // try the declared type try { return(Activator.CreateInstance(_target_type)); } catch { } // or in some cases it may happen, that the node has the name of the type { var type = _config.Processor.GetTypeByName(_parent_element.Name, _config); try { return(Activator.CreateInstance(type)); } catch { } } return(null); }
/// <inheritdoc /> public virtual object ProcessElements(XmlElement _parent_element, Type _target_type, X2OConfig _config) { var inst = CreateInstance(_parent_element, _target_type, _config); if (inst == null) { return(null); } foreach (XmlElement element in _parent_element.ChildNodes) { var member_info = inst.GetType().GetMembers().Single(m => m.Name == element.Name); var member_type = member_info.GetTypeOfMember(); var val = _config.Processor.ProcessElements(element, member_type, _config); member_info.SetMemberValue(inst, val); } return(inst); }