예제 #1
0
        public EnumerableBuilder(Builder <T> singleObjBuilder)
        {
            SingleObjBuilder = singleObjBuilder ?? throw new ArgumentNullException(nameof(singleObjBuilder));

            var values = Expression.Parameter(typeof(IEnumerable <>).MakeGenericType(new [] { typeof(T) }));

            var(isCollection, createExpression) = Enumerables.CreateCollectionExpression(
                typeof(TCollection),
                values);

            // will not occur because of generic constraint
            if (!isCollection)
            {
                throw new InvalidOperationException($"Type {typeof(TCollection)} must be an IEnumerable<>");
            }

            CollectionBuilder = EnsureCollectionIsNotIEnumerable(Expression
                                                                 .Lambda <Func <IEnumerable <T>, TCollection> >(createExpression, values))
                                .Compile();
        }
예제 #2
0
        /// <summary>
        /// Get a function which converts from IEnumerable -> propertyType. If no function found, falls back to casting
        /// </summary>
        static Func <IEnumerable, ILogger, TCollection> BuildEnumerableConvertor <TCollection, T>(bool cellTypeIsEnumerable) //bool resultIsCollectionOfCellsCCC, bool cellTypeIsEnumerableCCC)
            where TCollection : IEnumerable <T>
        {
            var innerConvertor = GetConvertor <T>(cellTypeIsEnumerable);

            var createCollectionInput = Expression.Parameter(typeof(IEnumerable <T>));

            var(isCollection, builder) = Enumerables.CreateCollectionExpression(typeof(TCollection), createCollectionInput);
            if (!isCollection)
            {
                throw new InvalidOperationException($"Unable to create collection expressoin for collection: {typeof(TCollection)}");
            }

            var createCollection = Expression
                                   .Lambda <Func <IEnumerable <T>, TCollection> >(builder, createCollectionInput)
                                   .Compile();

            var collectionIsNullable = typeof(TCollection).IsInterface ||
                                       !typeof(TCollection).IsValueType ||
                                       ReflectionUtils.IsNullable(typeof(TCollection));
            var innerIsEnumerable = ReflectionUtils.GetIEnumerableType(typeof(T)) != null;

            return(Convert);

            TCollection Convert(IEnumerable input, ILogger logger)
            {
                if (input is TCollection)
                {
                    return((TCollection)input);
                }

                if (input == null || DBNull.Value.Equals(input))
                {
                    if (collectionIsNullable)
                    {
                        return(default(TCollection));
                    }

                    throw new InvalidOperationException($"Cannot use value of null for type {typeof(TCollection)}");
                }

                if (cellTypeIsEnumerable && !innerIsEnumerable && logger.CanLogWarning(LogMessages.InefficientCastWarning))
                {
                    var valsType = GetTypeString(input);
                    logger.LogWarning($"Converting {valsType} to type {typeof(TCollection)}. " +
                                      $"This conversion is inefficient. Consider changing the " +
                                      $"result data type to {valsType}", LogMessages.InefficientCastWarning);

                    /*original message:
                     * $"Converting {valsType} to type {collectionType} for property " +
                     *  $"\"{propertyName}\". This conversion is inefficient. Consider changing the " +
                     *  $"data type of \"{propertyName}\" to {valsType}" */
                }

                // ToArray ensures that properties of type IEnumerable<T> will
                // have a concrete type (and not an enumerator)
                var converted = ConvertToType(input, logger).ToArray();

                return(createCollection(converted));
            }

            IEnumerable <T> ConvertToType(IEnumerable values, ILogger logger)
            {
                foreach (var val in values)
                {
                    yield return(innerConvertor(val, logger));
                }
            }
        }
예제 #3
0
 public Builder()
 {
     BuildObject         = Objects.CompileObjectBuilder <T>();
     AddEmptyEnumerables = Enumerables.CompileEnumerabeAdder <T>();
 }