Exemplo n.º 1
0
        /// <summary>
        /// Attempts to assign all the property&apos;s values on <see cref="fromObj"/> to
        /// some property on <see cref="toObj"/> based on the closest matching name.
        /// </summary>
        /// <param name="fromObj"></param>
        /// <param name="toObj"></param>
        /// <returns>1.0 when it was a perfect match</returns>
        /// <remarks>
        /// Use the <see cref="GetAssignPropertiesData"/> to see what it ended up choosing.
        /// </remarks>
        public static double TryAssignProperties(object fromObj, object toObj)
        {
            if (fromObj == null || toObj == null)
            {
                return(0);
            }
            var rScores     = new List <Tuple <int, int> >();
            var prevActions = new Dictionary <string, int>();

            try
            {
                //remove any previous records.
                assignPiLog.Clear();

                //only fromObj's value-type props
                rScores.AddRange(TryAssignValueTypeProperties(fromObj, toObj, prevActions));

                //only fromObj's ref-type props
                foreach (var fromPi in fromObj.GetType().GetProperties(DefaultFlags))
                {
                    if (fromPi == null || !fromPi.CanRead)
                    {
                        continue;
                    }

                    if (NfReflect.IsValueTypeProperty(fromPi, true))
                    {
                        continue;
                    }

                    var fromPv = fromPi.GetValue(fromObj);
                    if (fromPv == null && TryGetInstanceOfPiType(fromPi, out fromPv))
                    {
                        fromPi.SetValue(fromObj, fromPv);
                    }
                    rScores.AddRange(TryAssignValueTypeProperties(fromPv, toObj, prevActions, fromPi.Name));
                }
            }
            catch (Exception ex)
            {
                assignPiLog.Add(new[] { ERROR_PREFIX, ex.Message, ex.StackTrace });
                return(0);
            }
            var num   = rScores.Select(x => (double)x.Item2).Sum();
            var den   = rScores.Select(x => (double)x.Item1).Sum();
            var ratio = den == 0.0D ? 0.0D : num / den;

            return(1D - ratio);
        }
Exemplo n.º 2
0
        internal static Action GetSimpleAssignment(PropertyInfo toPi, object toObj, PropertyInfo fromPi, object fromObj, out string logInfo)
        {
            Action noop = () => { };

            logInfo = null;
            if (toPi == null || toObj == null || fromPi == null || fromObj == null)
            {
                return(noop);
            }

            //only deal in value types to value types
            if (!NfReflect.IsValueTypeProperty(toPi, true) || !NfReflect.IsValueTypeProperty(fromPi, true))
            {
                return(noop);
            }

            //enums require alot of special handling especially when wrapped in Nullable`1[
            var cpiIsEnum    = NfReflect.IsPropertyEnum(toPi);
            var fromPiIsEnum = NfReflect.IsPropertyEnum(fromPi);

            //get each pi's type
            var cpiType    = cpiIsEnum ? NfReflect.GetEnumType(toPi) : NfReflect.GetPropertyValueType(toPi);
            var fromPiType = fromPiIsEnum ? NfReflect.GetEnumType(fromPi) : NfReflect.GetPropertyValueType(fromPi);

            //get each pi's type's full name
            var cpiTypeFullname    = cpiType.FullName;
            var fromPiTypeFullname = fromPiType.FullName;

            logInfo = String.Join("->", fromPiTypeFullname, cpiTypeFullname);

            //easy assignment for same types
            if (cpiTypeFullname == fromPiTypeFullname)
            {
                return(() => toPi.SetValue(toObj, fromPi.GetValue(fromObj)));
            }

            //going from Enum to a string
            if (fromPiIsEnum && cpiTypeFullname == STR_FN)
            {
                //take enum value and get its name
                return(() =>
                {
                    var enumName = Enum.GetName(fromPiType, fromPi.GetValue(fromObj));
                    if (enumName != null)
                    {
                        toPi.SetValue(toObj, enumName);
                    }
                });
            }

            //going from a string to an enum
            if (cpiIsEnum && fromPiTypeFullname == STR_FN)
            {
                return(() =>
                {
                    var val = fromPi.GetValue(fromObj);
                    if (val != null && !String.IsNullOrWhiteSpace(val.ToString()) &&
                        Enum.GetNames(cpiType)
                        .Any(x => String.Equals(x, val.ToString(), StringComparison.OrdinalIgnoreCase)))
                    {
                        var enumVal = Enum.Parse(cpiType, val.ToString(), true);
                        toPi.SetValue(toObj, enumVal);
                    }
                });
            }

            //going from enum to enum
            if (fromPiIsEnum && cpiIsEnum)
            {
                //will this require any cast?
                return(() =>
                {
                    toPi.SetValue(toObj, fromPi.GetValue(fromObj));
                });
            }

            //going from some value-type to a string
            if (cpiTypeFullname == STR_FN)
            {
                return(() => toPi.SetValue(toObj, fromPi.GetValue(fromObj).ToString()));
            }

            //going from something to value-type
            switch (cpiTypeFullname)
            {
            case "System.Byte":
                return(() =>
                {
                    byte bout;
                    var bpiv = fromPi.GetValue(fromObj);
                    var byteString = bpiv == null ? "0" : bpiv.ToString();
                    if (Byte.TryParse(byteString, out bout))
                    {
                        toPi.SetValue(toObj, bout);
                    }
                });

            case "System.Int16":
                return(() =>
                {
                    short vout;
                    var piv = fromPi.GetValue(fromObj);
                    var vStr = piv == null ? "0" : piv.ToString();
                    if (Int16.TryParse(vStr, out vout))
                    {
                        toPi.SetValue(toObj, vout);
                    }
                });

            case "System.Int32":
                return(() =>
                {
                    int vout;
                    var piv = fromPi.GetValue(fromObj);
                    var vStr = piv == null ? "0" : piv.ToString();
                    if (Int32.TryParse(vStr, out vout))
                    {
                        toPi.SetValue(toObj, vout);
                    }
                });

            case "System.DateTime":
                return(() =>
                {
                    DateTime vout;
                    var piv = fromPi.GetValue(fromObj);
                    var vStr = piv == null ? "0" : piv.ToString();
                    if (DateTime.TryParse(vStr, out vout))
                    {
                        toPi.SetValue(toObj, vout);
                    }
                });

            case "System.Decimal":
                return(() =>
                {
                    decimal vout;
                    var piv = fromPi.GetValue(fromObj);
                    var vStr = piv == null ? "0" : piv.ToString();
                    if (Decimal.TryParse(vStr, out vout))
                    {
                        toPi.SetValue(toObj, vout);
                    }
                });

            case "System.Single":
                return(() =>
                {
                    float vout;
                    var piv = fromPi.GetValue(fromObj);
                    var vStr = piv == null ? "0" : piv.ToString();
                    if (Single.TryParse(vStr, out vout))
                    {
                        toPi.SetValue(toObj, vout);
                    }
                });

            case "System.Double":
                return(() =>
                {
                    double vout;
                    var piv = fromPi.GetValue(fromObj);
                    var vStr = piv == null ? "0" : piv.ToString();
                    if (Double.TryParse(vStr, out vout))
                    {
                        toPi.SetValue(toObj, vout);
                    }
                });
            }

            //default out to no operation
            return(noop);
        }
Exemplo n.º 3
0
        internal static List <Tuple <int, int> > TryAssignValueTypeProperties(object fromObj, object toObj, Dictionary <string, int> prevActions, string contextName = null)
        {
            var df = new List <Tuple <int, int> > {
                new Tuple <int, int>(Int32.MaxValue, 0)
            };

            if (fromObj == null || toObj == null)
            {
                return(df);
            }
            var rScores = new List <Tuple <int, int> >();

            try
            {
                var fromObjTypeName      = fromObj.GetType().FullName;
                var fromObjPropertyNames = fromObj.GetType().GetProperties(DefaultFlags).Select(p => p.Name).ToArray();

                //if still nothing found - just leave
                if (!fromObjPropertyNames.Any())
                {
                    return(df);
                }

                var toPis = toObj.GetType().GetProperties(DefaultFlags);
                prevActions = prevActions ?? new Dictionary <string, int>();

                foreach (var pn in fromObjPropertyNames)
                {
                    var fromPi = fromObj.GetType().GetProperty(pn);

                    if (fromPi == null || !fromPi.CanRead || !NfReflect.IsValueTypeProperty(fromPi, true))
                    {
                        continue;
                    }
                    //this will get us those closest on name only
                    var closestMatches = GetClosestMatch(fromPi, fromObj, toPis, toObj);
                    if (closestMatches == null || !Enumerable.Any <Tuple <Action, int, string, string> >(closestMatches))
                    {
                        continue;
                    }

                    //have to decide how to break a tie
                    if (closestMatches.Count > 1)
                    {
                        closestMatches = Enumerable.Where <Tuple <Action, int, string, string> >(closestMatches, x => x.Item3.Contains(pn)).ToList();
                    }
                    foreach (var cm in closestMatches)
                    {
                        //its possiable that two different pi names are both attempting to write to the exact same target pi in toObj
                        if (prevActions.ContainsKey(cm.Item3) && cm.Item2 >= prevActions[cm.Item3])
                        {
                            //we only want the one with the shortest distance
                            continue;
                        }

                        //exec the assignment on the target
                        cm.Item1();

                        //get this distance as a ratio to the possible max distance
                        rScores.Add(new Tuple <int, int>(cm.Item2, pn.Length));

                        //add this to the log
                        var logPn   = !String.IsNullOrWhiteSpace(contextName) ? String.Join(".", contextName, pn) : pn;
                        var logPath = !String.IsNullOrWhiteSpace(contextName) ? String.Join("`", fromObjTypeName, cm.Item4) : cm.Item4;
                        assignPiLog.Add(new[] { logPn, cm.Item3, logPath, cm.Item2.ToString() });

                        prevActions.Add(cm.Item3, cm.Item2);
                    }
                }
            }
            catch (Exception ex)
            {
                assignPiLog.Add(new[] { ERROR_PREFIX, ex.Message, ex.StackTrace });
                return(df);
            }

            //return average
            return(rScores);
        }
Exemplo n.º 4
0
        internal static List <Tuple <Action, int, string, string> > GetClosestMatch(PropertyInfo fromPi, object fromObj, PropertyInfo[] toPis, object toObj, string namePrefix = null, int minLen = 2)
        {
            if (fromPi == null || toPis == null || !toPis.Any())
            {
                return(new List <Tuple <Action, int, string, string> >());
            }

            //we want to map a whole assignment expression to a distance on name
            var ops2Score = new List <Tuple <Action, int, string, string> >();

            Func <PropertyInfo, string, bool, string> getMeasureableName = (gmnPi, prefix, inReverse) =>
            {
                if (gmnPi.Name.Length <= minLen)
                {
                    return(inReverse ? String.Join("", gmnPi.Name, prefix) : String.Join("", prefix, gmnPi.Name));
                }
                return(gmnPi.Name);
            };

            foreach (var toPi in toPis)
            {
                if (NfReflect.IsValueTypeProperty(toPi, true))
                {
                    string toFromTns;
                    Action simpleAssignment = GetSimpleAssignment(toPi, toObj, fromPi, fromObj, out toFromTns);
                    if (String.IsNullOrWhiteSpace(namePrefix))
                    {
                        //for simple value types -to- value types where dest has a very short name
                        namePrefix = toObj.GetType().Name;
                    }
                    var fromPiName        = getMeasureableName(fromPi, namePrefix, false);
                    var cpiName           = getMeasureableName(toPi, namePrefix, false);
                    var fromPiReverseName = getMeasureableName(fromPi, namePrefix, true);
                    var cpiReverseName    = getMeasureableName(toPi, namePrefix, true);

                    var score = (int)NfString.LevenshteinDistance(fromPiName, cpiName);

                    //with short property names, prehaps a better score is when prefix is a suffix instead
                    if (fromPiName != fromPiReverseName || cpiName != cpiReverseName)
                    {
                        var revScore = (int)NfString.LevenshteinDistance(fromPiReverseName, cpiReverseName);
                        if (revScore < score)
                        {
                            score = revScore;
                        }
                    }

                    ops2Score.Add(new Tuple <Action, int, string, string>(simpleAssignment, score, toPi.Name, toFromTns));
                }
                else
                {
                    var toInnerPi = toPi.PropertyType.GetProperties(DefaultFlags);
                    if (!toInnerPi.Any())
                    {
                        continue;
                    }

                    var toInnerObj        = toPi.GetValue(toObj) ?? Activator.CreateInstance(toPi.PropertyType);
                    var innerMeasurements = GetClosestMatch(fromPi, fromObj, toInnerPi, toInnerObj, toPi.Name, minLen);

                    if (!innerMeasurements.Any())
                    {
                        continue;
                    }

                    //these will by def, be the shortest distance
                    foreach (var innerM in innerMeasurements)
                    {
                        //we will chain-link these actions
                        Action complexAction = () =>
                        {
                            innerM.Item1();
                            if (toPi.GetValue(toObj) == null)
                            {
                                toPi.SetValue(toObj, toInnerObj);
                            }
                        };
                        var actionId = String.Join(".", toPi.Name, innerM.Item3);

                        ops2Score.Add(new Tuple <Action, int, string, string>(complexAction, innerM.Item2, actionId, String.Join("`", toPi.PropertyType.FullName, innerM.Item4)));
                    }
                }
            }

            var totalMin = ops2Score.Min(x => x.Item2);
            var closest  = ops2Score.Where(x => x.Item2 == totalMin).ToList();

            return(closest);
        }
Exemplo n.º 5
0
        //[EditorBrowsable(EditorBrowsableState.Never)]
        public static List <FlattenedLine> FlattenType(Assembly assembly, string typeFullName,
                                                       ref int currentDepth, int maxDepth, string limitOnValueType, bool displayEnums, Stack <FlattenedItem> fiValueTypes, Stack typeStack)
        {
            var printList = new List <FlattenedLine>();

            if (string.IsNullOrWhiteSpace(typeFullName))
            {
                return(printList);
            }

            Func <PropertyInfo, string, bool> limitOnPi =
                (info, s) =>
                string.IsNullOrWhiteSpace(s) ||
                string.Equals($"{info.PropertyType}", s, StringComparison.OrdinalIgnoreCase) ||
                string.Equals(NfReflect.GetLastTypeNameFromArrayAndGeneric(info.PropertyType), s,
                              StringComparison.OrdinalIgnoreCase) ||
                (s == Constants.ENUM && NfReflect.IsEnumType(info.PropertyType));

            var currentType = assembly.NfGetType(typeFullName);

            if (currentType == null)
            {
                return(printList);
            }

            //top frame of recursive calls will perform this
            if (fiValueTypes == null)
            {
                if (maxDepth <= 0)
                {
                    maxDepth = 16;
                }
                typeStack = new Stack();
                typeStack.Push(typeFullName);
                fiValueTypes = new Stack <FlattenedItem>();
                fiValueTypes.Push(new FlattenedItem(currentType)
                {
                    FlName = NfReflect.GetTypeNameWithoutNamespace(typeFullName)
                });
            }

            var typeNamesList =
                currentType.GetProperties(NfSettings.DefaultFlags)
                .Where(
                    x =>
                    (NfReflect.IsValueTypeProperty(x) && limitOnPi(x, limitOnValueType) ||
                     (limitOnValueType == Constants.ENUM && limitOnPi(x, limitOnValueType)))
                    //more limbo branching for enums
                    )
                .Select(p => new Tuple <Type, string>(p.PropertyType, p.Name))
                .ToList();


            foreach (var typeNamePair in typeNamesList)
            {
                var pVtype = typeNamePair.Item1;
                var pVname = typeNamePair.Item2;

                fiValueTypes.Push(new FlattenedItem(pVtype)
                {
                    FlName = pVname
                });
                var fiItems = fiValueTypes.ToList();
                fiItems.Reverse();
                printList.Add(new FlattenedLine(fiItems.Distinct(new FlattenedItemComparer()).ToList())
                {
                    ValueType = $"{typeNamePair.Item1}"
                });
                fiValueTypes.Pop();
            }

            //then recurse the object types
            foreach (
                var p in
                currentType.GetProperties(NfSettings.DefaultFlags)
                .Where(x => !NfReflect.IsValueTypeProperty(x)))
            {
                currentDepth += 1;

                //time to go
                if (currentDepth >= maxDepth)
                {
                    return(printList);
                }

                var typeIn = NfReflect.GetLastTypeNameFromArrayAndGeneric(p.PropertyType);

                if (typeIn == null || typeStack.Contains(typeIn))
                {
                    continue;
                }

                var fi = new FlattenedItem(p.PropertyType)
                {
                    FlName = p.Name
                };
                if (fiValueTypes.ToList().Any(x => x.FlType == p.PropertyType))
                {
                    continue;
                }

                fiValueTypes.Push(fi);
                typeStack.Push(typeIn);

                //enum types being handled as limbo between value type and ref type
                string[] enumVals;
                if (displayEnums && NfReflect.IsEnumType(p.PropertyType, out enumVals))
                {
                    foreach (var ev in enumVals)
                    {
                        fiValueTypes.Push(new FlattenedItem(typeof(Enum))
                        {
                            FlName = ev
                        });
                        var fiItems = fiValueTypes.ToList();
                        fiItems.Reverse();
                        printList.Add(new FlattenedLine(fiItems.Distinct(new FlattenedItemComparer()).ToList())
                        {
                            ValueType = String.Empty
                        });
                        fiValueTypes.Pop();
                    }
                }
                else
                {
                    printList.AddRange(FlattenType(assembly, fi.TypeFullName, ref currentDepth, maxDepth,
                                                   limitOnValueType, displayEnums, fiValueTypes, typeStack));
                }

                fiValueTypes.Pop();
                typeStack.Pop();
                currentDepth -= 1;
            }
            return(printList);
        }