public void AddChildren(TrieNodeProperty child) { if (Children == null) { Children = new List <TrieNodeProperty>(); } Children.Add(child); }
/// <summary> /// Start the auto mapping process, this initializes memory and assigns value /// </summary> /// <param name="destination"></param> /// <param name="source"></param> /// <param name="propertyNode"></param> /// <param name="preserveExistingValue"></param> private static void StartAutoMappingProcess(TrieNodeProperty destinationNode, TrieNodeProperty sourcePropertyNodes, bool preserveExistingValue = false) { //Get the top most node in the tree TrieNodeProperty topMostNode = sourcePropertyNodes.GetTopMostRoot(); //Map the source to the destination MapSourceToDestination(destinationNode, topMostNode); }
public TrieNodeProperty GetTopMostRoot() { TrieNodeProperty topMostNode = this; while (!topMostNode.IsTopMostRoot()) { topMostNode = topMostNode.Parent; } return(topMostNode); }
public TrieNodeProperty(TrieNodeProperty parentProperty, PropertyInfo currentProperty, object instance) { Parent = parentProperty; Property = currentProperty; if (parentProperty != null) { parentProperty.AddChildren(this); } Instance = instance; PreserveExisting = false; }
/// <summary> /// /// </summary> /// <param name="property"></param> /// <param name="propertyMap"></param> private static void GetSubProperties(PropertyInfo property, TrieNodeProperty propertyMap) { //Create the object TRIE var propertyInstance = property.GetValue(propertyMap.Instance); propertyMap = new TrieNodeProperty(propertyMap, property, propertyInstance); //Map the Sub properties if (IsClass(property)) { //Get all the properties that are public var subProperties = property.PropertyType .GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(x => x.GetMethod != null && !x.GetMethod.IsPrivate && x.SetMethod != null && !x.SetMethod.IsPrivate) .ToList(); //Get the could of properties that are public var publicPropertiesCount = subProperties.Count; //Filter null properties subProperties = subProperties .Where(x => x.GetValue(propertyInstance) != null) .ToList(); //Filter out value types with default value subProperties.ToList().ForEach(prop => { if (prop.PropertyType.IsValueType && object.Equals(prop.GetValue(propertyInstance), Activator.CreateInstance(prop.PropertyType))) { subProperties.Remove(prop); } }); //Get the new count of properties after filtering var filteredPublicPropertiesCount = subProperties.Count; //if the count does not match, then preserve existings if (filteredPublicPropertiesCount > 0 && publicPropertiesCount != filteredPublicPropertiesCount) { propertyMap.PreserveExisting = true; } //Iterate the sub properties subProperties.ForEach(subproperty => { GetSubProperties(subproperty, propertyMap); }); } }
/// <summary> /// Get the properties of object map and index them. /// </summary> /// <param name="property">Property</param> /// <param name="parentPropertyName">Parent Property Name</param> /// <param name="propertyMappingIndex">Index of the object mapping</param> /// <param name="propertyMap">Property Node</param> /// <param name="propertyDepth">Current Depth of the scan</param> private static void GetProperties(PropertyInfo property, string parentPropertyName, Dictionary <Type, Dictionary <string, TrieNodeProperty> > propertyMappingIndex, TrieNodeProperty parentProperty) { string propertyName = string.Empty; object propertyInstance = null; //Check the instance of parent property if (parentProperty.Instance != null) { propertyInstance = property.GetValue(parentProperty.Instance); } //Create the TRIE node parentProperty = new TrieNodeProperty(parentProperty, property, propertyInstance); propertyName = parentPropertyName.ToUpper(); //Start indexing the property if (propertyMappingIndex.ContainsKey(property.PropertyType)) { var propertiesList = propertyMappingIndex[property.PropertyType]; propertiesList.Add(propertyName, parentProperty); } else { propertyMappingIndex.Add(property.PropertyType, new Dictionary <string, TrieNodeProperty>() { { propertyName, parentProperty } }); } //Map the Sub properties if (IsClass(property)) { var subProperties = property.PropertyType .GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(x => x.GetMethod != null && !x.GetMethod.IsPrivate && x.SetMethod != null && !x.SetMethod.IsPrivate) .ToList(); subProperties.ForEach(subproperty => { propertyName = $"{parentPropertyName}.{subproperty.Name}"; GetProperties(subproperty, propertyName, propertyMappingIndex, parentProperty); }); } }
/// <summary> /// Go over the properties and map them to the target (destination) /// </summary> /// <param name="targetTrieNode">Target Trie node</param> /// <param name="sourcePropertyNode">Source Trie Node</param> private static void MapSourceToDestination(TrieNodeProperty targetTrieNode, TrieNodeProperty sourcePropertyNode) { if (IsClass(targetTrieNode.Property) && targetTrieNode.Instance != null && !sourcePropertyNode.HasChildren()) { return; } //If the target Instance is null, that mean the property is null if (targetTrieNode.Instance == null) { //get the parent instance and assign the source directly to that. var parentInstance = targetTrieNode.GetParent().Instance; AssignSourceToDestination(parentInstance, parentInstance, sourcePropertyNode.Instance, targetTrieNode.Property); return; } if (sourcePropertyNode.HasChildren()) { //Since the property has children, then we go deeper perform mapping on them //Iterate over each sub property and perform the mapping sourcePropertyNode.Children.ForEach(childProperty => { var targetChildProperty = targetTrieNode.Instance.GetType().GetProperty(childProperty.Property.Name); var targetPropertyInstance = targetChildProperty.GetValue(targetTrieNode.Instance); if (targetPropertyInstance == null) { AssignSourceToDestination(targetTrieNode.Instance, targetTrieNode.Instance, childProperty.Instance, targetChildProperty); return; } var targetNode = new TrieNodeProperty(targetTrieNode, targetChildProperty, targetPropertyInstance); MapSourceToDestination(targetNode, childProperty); }); } else { //Else - this means the property has no more child properties or you have reached the last property. //Map directly var targetChildProperty = targetTrieNode.Property; var targetPropertyInstance = targetTrieNode.GetParent().Instance; AssignSourceToDestination(targetPropertyInstance, targetPropertyInstance, sourcePropertyNode.Instance, targetChildProperty); } }
public static void Map(this object destination, object source, string propertyName, bool preserveExistingValue = false) { if (destination == null) { throw new NullArgumentException("The desination object (object to which the mapping has to happen) is null", $"{GetCurrentMethodName()}"); } if (source == null) { throw new NullArgumentException("The source object (object from which the mapping has to happen) is null", $"{GetCurrentMethodName()}"); } //Get the source and target object type var destinationType = destination.GetType(); var sourceType = source.GetType(); if (object.Equals(destinationType, sourceType)) { destination = source; return; } //If the destinaton type and source type are same and //destination is a list or array, then just assign source //Locate the correct property and instance on which the mapping has to happen TrieNodeProperty destinationNode = LocateSourcePropertyTypeInDestination(destination, source, propertyName); AutoInitialize(destinationNode); if (sourceType.IsGenericType || sourceType.IsArray) { var existingValue = destinationNode.Property.GetValue(destinationNode.GetParent().Instance); AssignSourceToDestination(destinationNode.GetParent().Instance, existingValue, source, destinationNode.Property); return; } //Property Trie - Make the top most root, doesn't have a value or a parent TrieNodeProperty sourcePropertyNode = LoadSourceObjectDictionary(source); //Start mapping, auto memory initializationa and value assigning StartAutoMappingProcess(destinationNode, sourcePropertyNode, preserveExistingValue); }
/// <summary> /// Map the Object dictionary /// </summary> /// <param name="destination">Destination object</param> /// <param name="propertyMapping">Property mapping dictionary</param> private static TrieNodeProperty LoadSourceObjectDictionary(object source) { TrieNodeProperty propertyMappedTrie = new TrieNodeProperty(null, null, source); var publicProperties = source.GetType() .GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(x => x.GetMethod != null && !x.GetMethod.IsPrivate && x.SetMethod != null && !x.SetMethod.IsPrivate) .ToList(); var publicPropertiesCount = publicProperties.Count; publicProperties = publicProperties .Where(x => x.GetValue(source) != null) .ToList(); //Filter out value types with default values publicProperties.ToList().ForEach(prop => { if (prop.PropertyType.IsValueType && object.Equals(prop.GetValue(source), Activator.CreateInstance(prop.PropertyType))) { publicProperties.Remove(prop); } }); var filteredPublicPropertiesCount = publicProperties.Count; if (filteredPublicPropertiesCount > 0 && publicPropertiesCount != filteredPublicPropertiesCount) { propertyMappedTrie.PreserveExisting = true; } publicProperties.ForEach(property => { GetSubProperties(property, propertyMappedTrie); }); return(propertyMappedTrie); }
/// <summary> /// Auto Initialize the parent Instances /// </summary> /// <param name="targetTrieNode"></param> private static void AutoInitialize(TrieNodeProperty targetTrieNode) { Stack <TrieNodeProperty> initializationOrder = new Stack <TrieNodeProperty>(); //Create a stack order for intialization while (!targetTrieNode.IsTopMostRoot() && targetTrieNode.HasParent()) { targetTrieNode = targetTrieNode.GetParent(); var objectInstance = targetTrieNode.Instance; if (objectInstance == null) { initializationOrder.Push(targetTrieNode); } } //Start creating initializing the objects while (initializationOrder.Count > 0) { var node = initializationOrder.Pop(); var objectInstance = CreateInstanceOfType(node.Property.PropertyType); node.SetInstance(objectInstance); } }
/// <summary> /// Map the Object dictionary /// </summary> /// <param name="destination">Destination object</param> /// <param name="propertyMapping">Property mapping dictionary</param> private static Dictionary <Type, Dictionary <string, TrieNodeProperty> > LoadDestinationPropertyMap(object destination) { Dictionary <Type, Dictionary <string, TrieNodeProperty> > propertyMapping = new Dictionary <Type, Dictionary <string, TrieNodeProperty> >(); TrieNodeProperty rootNode = new TrieNodeProperty(null, null, destination); var publicProperties = destination.GetType() .GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(x => x.GetMethod != null && !x.GetMethod.IsPrivate && x.SetMethod != null && !x.SetMethod.IsPrivate) .ToList(); publicProperties.ForEach(property => { GetProperties(property, property.Name, propertyMapping, rootNode); }); return(propertyMapping); }