/// <summary>Given an istance of an object T, create a hash for field values we want to track a change in</summary>
        /// <typeparam name="T">Object type</typeparam>
        /// <param name="obj">object instance</param>
        /// <returns></returns>
        /// <remarks>
        /// https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html
        /// https://msdn.microsoft.com/en-us/library/system.object.gethashcode(v=vs.110).aspx
        /// </remarks>
        public static int HashByValue <T>(T obj)
        {
            // get only public instance properties
            PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);

            // track a running hash value
            int hash = 0;

            foreach (PropertyInfo prop in props)
            {
                // ignore if not a public read property
                if (!prop.CanRead)
                {
                    continue;
                }

                // get the properties TrackChange attribute
                TrackAttribute map = prop.GetCustomAttribute <TrackAttribute>(false);

                // has a Track attribute set to true
                if (map != null && map.TrackChange)
                {
                    object value = prop.GetValue(obj, null);

                    if (value == null)
                    {
                        hash = hash ^ 0;
                    }
                    // make null strings and empty strings cause the same value since they might be read from different sources
                    else if (prop.PropertyType == typeof(string) && String.IsNullOrWhiteSpace(value.ToString()))
                    {
                        hash = hash ^ 0;
                    }
                    else
                    {
                        hash = hash ^ value.GetHashCode();
                    }
                }
            }

            return(hash);
        }
        /// <summary>Forms a string to determine if the object is the same</summary>
        /// <remarks>strings are NOT case sensitive</remarks>
        public static string HashByString <T>(T obj)
        {
            // get all the properties in the class
            PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);

            // concatenate every field we care about
            StringBuilder sb = new StringBuilder();

            foreach (PropertyInfo prop in props)
            {
                // is this a public read property
                if (!prop.CanRead)
                {
                    continue;
                }

                // get the properties FieldMap attribute
                TrackAttribute map = prop.GetCustomAttribute <TrackAttribute>(false);

                if (map != null && map.TrackChange)
                {
                    // null values add nothing to the hash
                    object value = prop.GetValue(obj, null);

                    if (value == null)
                    {
                        continue;
                    }

                    // change to switch

                    if (prop.PropertyType == typeof(string))
                    {
                        sb.Append(value.ToString().Trim().ToLower());
                    }
                    else if (prop.PropertyType == typeof(bool) || prop.PropertyType == typeof(Nullable <bool>))
                    {
                        sb.Append(value.ToString().ToLower()[0]);
                    }
                    else if (prop.PropertyType == typeof(DateTime) || prop.PropertyType == typeof(Nullable <DateTime>))
                    {
                        sb.Append(value.ToString().ToLower());
                    }
                    else if (prop.PropertyType == typeof(int) || prop.PropertyType == typeof(Nullable <int>))
                    {
                        sb.Append(value.ToString());
                    }
                    else if (prop.PropertyType == typeof(long) || prop.PropertyType == typeof(Nullable <long>))
                    {
                        sb.Append(value.ToString());
                    }
                    else if (prop.PropertyType.IsEnum)
                    {
                        sb.Append(Convert.ToInt32(value));
                    }
                    else
                    {
                        throw new System.Exception("Unknown type in the Hash Comparison.");
                    }
                }
            }

            return(sb.ToString());
        }