Ejemplo n.º 1
0
        /// <summary>
        /// Gets all the fields AND properties with their correct names.
        /// </summary>
        /// <returns>The fields and properties.</returns>
        public static ABSaveObjectItems GetFieldsAndPropertiesWithTypes(Type objType)
        {
            // Make a name/value/type dictionary - this is what we'll return.
            var ret = new ABSaveObjectItems();

            // Get all the fields.
            var fieldNames = objType.GetFields();

            // Add all the fields to the dictionary.
            for (int i = 0; i < fieldNames.Count(); i++)
            {
                ret.Add(fieldNames[i]);
            }

            // Return the final result.
            return(ret);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Gets all the fields AND properties with their correct names and values based on an object.
        /// </summary>
        /// <typeparam name="T">The type of the object we're getting values for.</typeparam>
        /// <returns>The fields/properties and values for the object.</returns>
        public static ABSaveObjectItems GetFieldsAndPropertiesWithValues(object obj)
        {
            // Get the type of the object to use in the rest of the method.
            var objType = obj.GetType();

            // Make a dictionary - this is what we'll return.
            var ret = new ABSaveObjectItems();

            // First of all, get all of the fields.
            var fields = objType.GetFields(BindingFlags.Public | BindingFlags.Instance);

            // Add all of the fields to the ObjectItems dictionary.
            for (int i = 0; i < fields.Count(); i++)
            {
                ret.Add(fields[i].GetValue(obj), fields[i]);
            }

            // Return the final result.
            return(ret);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Attempts to create an instance of an object, based on a NameValueTypeDictionary - if the object's constructors have parameters, we'll attempt to figure out how to use them.
        /// </summary>
        /// <typeparam name="T">The type of the object.</typeparam>
        /// <param name="settings">The way of handling any errors.</param>
        /// <param name="location">OPTIONAL: The location this happened in an ABSave string - used in any errors.</param>
        public static object CreateInstance(Type type, ABSaveSettings settings, ABSaveObjectItems values, int location = 0)
        {
            // =======================
            // Variables
            // =======================

            // First of all, get all the constructor out of the type.
            var constructors = type.GetConstructors();

            // Remember all the values if there was a constructor with "No Case Match".
            object[] noCaseMatchValues = new object[0];

            // Next, remember all the REMAINING values if there was a constructor with "No Case Match"
            ABSaveObjectItems noCaseMatchRemaining = null;

            // Also, if we don't find a perfect constructor and there's too many "No Case Match" constructor, it will cause an error, so remember if there are more than one "No Case Match" constructors.
            var multipleNoCaseMatchConstructors = false;

            // =======================
            // Each Constructor
            // =======================

            for (int i = 0; i < constructors.Length; i++)
            {
                // Keep track of whether all the parameters in this constructor are valid and how close they are to the real thing.
                var passed = ABSaveConstructorInferer.Failed;

                // Get all the parameters for this constructor.
                var parameters      = constructors[i].GetParameters();
                var parametersCount = parameters.Length;

                // If there aren't any parameters, this is the one we preferably want.
                if (parametersCount == 0)
                {
                    return(InsertValuesIntoObject(Activator.CreateInstance(type), values));
                }

                // Keep track of the parameters' values in order.
                var parametersArguments = new object[parametersCount];

                // Also, keep track of any objects we were unable to pass into this constructor.
                var remainingValues = new ABSaveObjectItems();

                // If there are too many parameters, this constructor won't work.
                if (parametersCount > values.Count)
                {
                    continue;
                }

                // =======================
                // Each Item - To Find A Matching Parameter
                // =======================

                for (int j = 0; j < values.Count; j++)
                {
                    // Whether a parameter was found or not.
                    var parameterFound = ABSaveConstructorInferer.Failed;

                    // The index of the best parameter for this value.
                    var bestParam = -1;

                    // =======================
                    // Each Parameter
                    // =======================

                    for (int k = 0; k < parametersCount; k++)
                    {
                        // If the types don't match, this parameter failed, so try a different one.
                        if (!(values.Items[j].Info.FieldType == parameters[k].ParameterType))
                        {
                            continue;
                        }

                        // Check if the names perfectly match now.
                        if (values.Items[k].Info.Name == parameters[j].Name)
                        {
                            // This parameter is perfect.
                            parameterFound = ABSaveConstructorInferer.Perfect;
                            bestParam      = k;

                            // We want to break out of the "parameter" loop since this is a perfect match and it can't be anything else.
                            break;
                        }

                        // Otherwise, try and ignore the case and see if that helps.
                        else if (values.Items[k].Info.Name.ToLower() == parameters[j].Name.ToLower())
                        {
                            // Set the bestParam so that we can remember which parameter this was.
                            bestParam = k;

                            // Now, make sure we set this as a POSSIBLE value for this parameter and see if any other fields would work better.
                            parameterFound = ABSaveConstructorInferer.NoCaseMatch;
                            continue;
                        }
                    }

                    // =======================
                    // Check Value Results
                    // =======================

                    // If it failed, add this as failed value since it obviously can't work, and try some others!
                    if (bestParam == -1)
                    {
                        remainingValues.Add(values.Items[j]);
                        continue;
                    }

                    // Now, set the main "passed" variable for this constructor to how well this value did - but, if the constructor is on "No Case Match", leave it, since we know that this parameter didn't fail.
                    // Essentially, when the constructor is on "NoCaseMatch" because one of the parameters doesn't match case, it doesn't matter what the others are, they can't fix that one parameter.
                    if (passed != ABSaveConstructorInferer.NoCaseMatch)
                    {
                        passed = parameterFound;
                    }

                    // Now that we've decided the best object for a certain parameter, add that as the value at the correct index.
                    parametersArguments[bestParam] = values.Items[j].Value;
                }

                // =======================
                // Check Constructor Results
                // =======================

                // If this was a perfect constructor, return this one - with all the remaining items getting added in!
                if (passed == ABSaveConstructorInferer.Perfect)
                {
                    return(InsertValuesIntoObject(Activator.CreateInstance(type, parametersArguments), remainingValues));
                }

                // If this constructor overall got a "No Case Match", attempt to place the values into the "noCaseMatchValues".
                if (passed == ABSaveConstructorInferer.NoCaseMatch)
                {
                    // Determine how many values we were actually able to fill in a parameter as well as how many the LAST "No Case Match" constructor did.
                    var filledParameters     = values.Count - remainingValues.Count;
                    var lastFilledParameters = (noCaseMatchRemaining == null) ? 0 : values.Count - noCaseMatchRemaining.Count;

                    // If there was already a "No Case Match"... and we CAN'T override the last one, make sure we remember there's too many.
                    if (noCaseMatchValues.Count() > 0 && ((lastFilledParameters == values.Count) || (lastFilledParameters > filledParameters)))
                    {
                        multipleNoCaseMatchConstructors = true;
                    }

                    // If we can override the last one, though, mark it as "false" since this is the parameter we need.
                    else
                    {
                        multipleNoCaseMatchConstructors = false;
                    }

                    // Now, place the current values/remaining values into the main arrays.
                    noCaseMatchValues    = parametersArguments;
                    noCaseMatchRemaining = remainingValues;
                }
            }

            // =======================
            // Check Final Results
            // =======================

            // If we made it here, it means there weren't any PERFECT ones, so, before we attempt anything, we'll want to throw an error if we have come across more than one "No Case Match" constructor (in which case we wouldn't know what to use).
            if (multipleNoCaseMatchConstructors)
            {
                settings.ErrorHandler.TooManyConstructorsWithDifferentCase(type, location);
            }

            // And, now see if there was a "No Case Match" one, if so, that's the constructor we need!
            if (noCaseMatchValues.Count() > 0)
            {
                return(InsertValuesIntoObject(Activator.CreateInstance(type, noCaseMatchValues), noCaseMatchRemaining));
            }

            // And, if we got all the way here - it failed completely.
            settings.ErrorHandler.InvalidConstructorsForCreatingObject(type, location);
            return(null);
        }