예제 #1
0
        /// <summary>
        /// Execute a query to copy and update an object.
        /// </summary>
        /// <typeparam name="TSource">Type of the object to 'copy and update'</typeparam>
        /// <param name="query">Query to execute</param>
        /// <param name="getPropertyOrFieldNameFromArgument">
        /// Returns the field/property name corresponding to a specified argument name.
        /// If not specified, pascal case convention is used.
        /// Only useful if you use a different naming convention for your members ('m_' prefix for example)
        /// </param>
        /// <returns>New object, with updated values</returns>
        public static TSource Create <TSource>(
            this CopyUpdateQuery <TSource> query,
            Func <string, string> getPropertyOrFieldNameFromArgument = null)
            where TSource : class
        {
            getPropertyOrFieldNameFromArgument = getPropertyOrFieldNameFromArgument ?? PascalCase.Convert;

            var typeToBuild = typeof(TSource);

            // Check if unique constructor is available
            var typeInfo  = typeToBuild.GetTypeInfo();
            var ctorInfos = typeInfo.DeclaredConstructors.Where(ctor => !ctor.IsStatic).ToList();

            if (1 != ctorInfos.Count())
            {
                throw new InvalidOperationException(
                          string.Format(
                              "Type {0} must only contain one constructor",
                              typeToBuild));
            }

            // Get constructor parameters
            var ctorInfo   = ctorInfos.First();
            var ctorParams = ctorInfo.GetParameters();

            var newValues = query.PropertyOrFieldValues.ToDictionary(keyValue => keyValue.Key, keyValue => keyValue.Value);

            // Get arguments values
            var arguments = new object[ctorParams.Length];

            for (int index = 0; index < ctorParams.Length; ++index)
            {
                var arg = ctorParams[index];
                var propertyOrFieldName = getPropertyOrFieldNameFromArgument(arg.Name);

                // Update value ?
                object newValue;
                if (newValues.TryGetValue(propertyOrFieldName, out newValue))
                {
                    arguments[index] = newValue;
                    continue;
                }

                // Get property/field value
                var valueAccessor = AccessorProvider(typeToBuild, propertyOrFieldName);
                arguments[index] = valueAccessor(query.Source);
            }

            var constructor = ConstructorProvider(ctorInfo);

            return((TSource)constructor(arguments));
        }
예제 #2
0
        /// <summary>
        /// Creates a query to copy and update an object.
        /// </summary>
        /// <typeparam name="TSource">Type of the object to 'copy and update'</typeparam>
        /// <typeparam name="TPropertyOrField">Type of the field/property to update</typeparam>
        /// <param name="query">Current query to update</param>
        /// <param name="propertyOrFieldSelector">Selector on the field/property to update</param>
        /// <param name="value">New value for the field/property</param>
        /// <returns>Query used to create the new desired object</returns>
        public static CopyUpdateQuery <TSource> With <TSource, TPropertyOrField>(
            this CopyUpdateQuery <TSource> query,
            Expression <Func <TSource, TPropertyOrField> > propertyOrFieldSelector,
            TPropertyOrField value)
            where TSource : class
        {
            // Get field/property name accessed by the selector
            var propertyOrFieldName = GetReturnedPropertyOrFieldName(propertyOrFieldSelector);

            // Create query
            return(new CopyUpdateQuery <TSource>(
                       query.Source,
                       query.PropertyOrFieldValues.Concat(KeyValuePair.Create(propertyOrFieldName, (object)value))));
        }