private static void PrepareMembersCallback(SharpYaml.Serialization.Descriptors.ObjectDescriptor objDesc, List <IMemberDescriptor> memberDescriptors) { var type = objDesc.Type; if (IdentifiableHelper.IsIdentifiable(type) && !typeof(IIdentifiable).IsAssignableFrom(type)) { memberDescriptors.Add(CustomDynamicMemberDescriptor); } // Call custom callbacks to prepare members PrepareMembersEvent?.Invoke(objDesc, memberDescriptors); }
private static void PrepareMembersCallback(SharpYaml.Serialization.Descriptors.ObjectDescriptor objDesc, List <IMemberDescriptor> memberDescriptors) { var type = objDesc.Type; // Early exit if we don't need to add a unique identifier to a type if (!IdentifiableHelper.IsIdentifiable(type) || typeof(IIdentifiable).IsAssignableFrom(type)) { return; } // Otherwise we can add it memberDescriptors.Add(CustomDynamicMemberDescriptor); }
public override string ReadMemberName(ref ObjectContext objectContext, string memberName, out bool skipMember) { var newMemberName = memberName.Trim(Override.PostFixSealed, Override.PostFixNew); var objectType = objectContext.Instance.GetType(); if (newMemberName.Length != memberName.Length) { var overrideType = OverrideType.Base; if (memberName.Contains(Override.PostFixNewSealed) || memberName.EndsWith(Override.PostFixNewSealedAlt)) { overrideType = OverrideType.New | OverrideType.Sealed; } else if (memberName.EndsWith(Override.PostFixNew)) { overrideType = OverrideType.New; } else if (memberName.EndsWith(Override.PostFixSealed)) { overrideType = OverrideType.Sealed; } if (overrideType != OverrideType.Base) { if (cachedDescriptor == null || cachedDescriptor.Type != objectType) { cachedDescriptor = typeDescriptorFactory.Find(objectType); } var memberDescriptor = cachedDescriptor[newMemberName]; objectContext.Instance.SetOverride(memberDescriptor, overrideType); } } var resultMemberName = base.ReadMemberName(ref objectContext, newMemberName, out skipMember); // If ~Id was not found as a member, don't generate an error, as we may have switched an object // to NonIdentifiable but we don't want to write an upgrader for this if (!IdentifiableHelper.IsIdentifiable(objectType) && memberName == IdentifiableHelper.YamlSpecialId) { skipMember = true; } return(resultMemberName); }
private void DiffValue(Diff3Node diff3, ref NodeDescription baseNodeDesc, ref NodeDescription asset1NodeDesc, ref NodeDescription asset2NodeDesc) { var node = diff3.Asset1Node ?? diff3.Asset2Node ?? diff3.BaseNode; var dataVisitMember = node as DataVisitMember; if (dataVisitMember != null) { var diffMember = dataVisitMember.MemberDescriptor.GetCustomAttributes <DiffMemberAttribute>(true).FirstOrDefault(); if (diffMember != null) { if (diffMember.PreferredChange.HasValue) { diff3.ChangeType = diffMember.PreferredChange.Value; } diff3.Weight = diffMember.Weight; } } var instanceType = asset1NodeDesc.Instance?.GetType() ?? asset2NodeDesc.Instance?.GetType(); object baseInstance = baseNodeDesc.Instance; object asset1Instance = asset1NodeDesc.Instance; object asset2Instance = asset2NodeDesc.Instance; // If this is an identifiable type (but we are for example not visiting its member), compare only the Ids instead if (UseOverrideMode && instanceType != null && IdentifiableHelper.IsIdentifiable(instanceType)) { baseInstance = IdentifiableHelper.GetId(baseInstance); asset1Instance = IdentifiableHelper.GetId(asset1Instance); asset2Instance = IdentifiableHelper.GetId(asset2Instance); } var baseAsset1Equals = Equals(baseInstance, asset1Instance); var baseAsset2Equals = Equals(baseInstance, asset2Instance); var asset1And2Equals = Equals(asset1Instance, asset2Instance); diff3.ChangeType = baseAsset1Equals && baseAsset2Equals ? Diff3ChangeType.None : baseAsset2Equals ? Diff3ChangeType.MergeFromAsset1 : baseAsset1Equals ? Diff3ChangeType.MergeFromAsset2 : asset1And2Equals ? Diff3ChangeType.MergeFromAsset1And2 : Diff3ChangeType.Conflict; }
private void DiffCollection(Diff3Node diff3, DataVisitNode baseNode, DataVisitNode asset1Node, DataVisitNode asset2Node) { diff3.Type = Diff3NodeType.Collection; var baseItems = baseNode != null ? baseNode.Items ?? EmptyNodes : EmptyNodes; var asset1Items = asset1Node != null ? asset1Node.Items ?? EmptyNodes : EmptyNodes; var asset2Items = asset2Node != null ? asset2Node.Items ?? EmptyNodes : EmptyNodes; var itemEqualityComparer = equalityComparer; var node = diff3.Asset1Node ?? diff3.Asset2Node ?? diff3.BaseNode; IEnumerable <Diff3Change> changes; bool recurseDiff = false; // Find an item in any of the list var firstItem = baseItems.FirstOrDefault(item => item.Instance != null) ?? asset1Items.FirstOrDefault(item => item.Instance != null) ?? asset2Items.FirstOrDefault(item => item.Instance != null); // For now, in the context of UseOverrideMode and we have identifiers per item, use DiffCollectionByIds instead if (UseOverrideMode && firstItem != null) { if (IdentifiableHelper.IsIdentifiable(firstItem.Instance.GetType())) { DiffCollectionByIds(diff3, baseNode, asset1Node, asset2Node); return; } else if (firstItem.Instance is Guid) { DiffCollectionByGuids(diff3, baseNode, asset1Node, asset2Node); return; } } // If we have a DiffUseAsset1Attribute, list of Asset1Node becomes authoritative. var dataVisitMember = node as DataVisitMember; var diffMemberAttribute = dataVisitMember != null?dataVisitMember.MemberDescriptor.GetCustomAttributes <DiffMemberAttribute>(true).FirstOrDefault() : null; if (diffMemberAttribute != null && diffMemberAttribute.PreferredChange.HasValue) { diff3.Weight = diffMemberAttribute.Weight; } if (diffMemberAttribute != null && diffMemberAttribute.PreferredChange.HasValue) { var diffChange = diffMemberAttribute.PreferredChange.Value == Diff3ChangeType.MergeFromAsset2 ? new Diff3Change { ChangeType = SharpDiff.Diff3ChangeType.MergeFrom2, From2 = new Span(0, asset2Items.Count - 1) } : new Diff3Change { ChangeType = SharpDiff.Diff3ChangeType.MergeFrom1, From1 = new Span(0, asset1Items.Count - 1) }; changes = new[] { diffChange }; // TODO: Try to merge back data of matching nodes } else if (firstItem != null && typeof(IDiffKey).IsAssignableFrom(firstItem.InstanceType)) { // If item implement IDataDiffKey, we will use that as equality key changes = Diff3.Compare( baseItems.Select(x => ((IDiffKey)x.Instance).GetDiffKey()).ToList(), asset1Items.Select(x => ((IDiffKey)x.Instance).GetDiffKey()).ToList(), asset2Items.Select(x => ((IDiffKey)x.Instance).GetDiffKey()).ToList()); recurseDiff = true; } else { // Otherwise, do a full node comparison itemEqualityComparer.Reset(); changes = Diff3.Compare(baseItems, asset1Items, asset2Items, itemEqualityComparer); } foreach (var change in changes) { switch (change.ChangeType) { case SharpDiff.Diff3ChangeType.Equal: for (int i = 0; i < change.Base.Length; i++) { var diff3Node = recurseDiff ? DiffNode(baseItems[change.Base.From + i], asset1Items[change.From1.From + i], asset2Items[change.From2.From + i]) : new Diff3Node(baseItems[change.Base.From + i], asset1Items[change.From1.From + i], asset2Items[change.From2.From + i]) { ChangeType = Diff3ChangeType.None }; AddItem(diff3, diff3Node, change.From1.From != 0); } break; case SharpDiff.Diff3ChangeType.MergeFrom1: for (int i = 0; i < change.From1.Length; i++) { var diff3Node = new Diff3Node(null, asset1Items[change.From1.From + i], null) { ChangeType = Diff3ChangeType.MergeFromAsset1 }; AddItem(diff3, diff3Node, change.From1.From != 0); } break; case SharpDiff.Diff3ChangeType.MergeFrom2: for (int i = 0; i < change.From2.Length; i++) { var diff3Node = new Diff3Node(null, null, asset2Items[change.From2.From + i]) { ChangeType = Diff3ChangeType.MergeFromAsset2 }; AddItem(diff3, diff3Node, true); } break; case SharpDiff.Diff3ChangeType.MergeFrom1And2: for (int i = 0; i < change.From2.Length; i++) { var diff3Node = recurseDiff ? DiffNode(null, asset1Items[change.From1.From + i], asset2Items[change.From2.From + i]) : new Diff3Node(null, asset1Items[change.From1.From + i], asset2Items[change.From2.From + i]) { ChangeType = Diff3ChangeType.MergeFromAsset1And2 }; AddItem(diff3, diff3Node, change.From1.From != 0); } break; case SharpDiff.Diff3ChangeType.Conflict: int baseIndex = change.Base.IsValid ? change.Base.From : -1; int from1Index = change.From1.IsValid ? change.From1.From : -1; int from2Index = change.From2.IsValid ? change.From2.From : -1; // If there are changes only from 1 or 2 or base.Length == list1.Length == list2.Length, then try to make a diff per item // else output the conflict as a full conflict bool tryResolveConflict = false; if (baseIndex >= 0) { if (from1Index >= 0 && from2Index >= 0) { if ((change.Base.Length == change.From1.Length && change.Base.Length == change.From2.Length) || (change.From1.Length == change.From2.Length)) { tryResolveConflict = true; } } else if (from1Index >= 0) { tryResolveConflict = change.Base.Length == change.From1.Length; } else if (from2Index >= 0) { tryResolveConflict = change.Base.Length == change.From2.Length; } else { tryResolveConflict = true; } } // Iterate on items while ((baseIndex >= 0 && baseItems.Count > 0) || (from1Index >= 0 && asset1Items.Count > 0) || (from2Index >= 0 && asset2Items.Count > 0)) { var baseItem = GetSafeFromList(baseItems, ref baseIndex, ref change.Base); var asset1Item = GetSafeFromList(asset1Items, ref from1Index, ref change.From1); var asset2Item = GetSafeFromList(asset2Items, ref from2Index, ref change.From2); var diff3Node = tryResolveConflict || recurseDiff? DiffNode(baseItem, asset1Item, asset2Item) : new Diff3Node(baseItem, asset1Item, asset2Item) { ChangeType = Diff3ChangeType.Conflict }; AddItem(diff3, diff3Node, true); } break; } } // Any missing item? (we can detect this only at the end) var newItemCount = diff3.Items != null ? diff3.Items.Count : 0; if (asset1Items.Count != newItemCount) { diff3.ChangeType = Diff3ChangeType.Children; } }