예제 #1
0
        public UninitialisedSourceToNullHandlingConverter(ICompilableTypeConverter <TSource, TDest> wrappedConverter, PropertyInfo sourceTypeIsInitialisedProperty)
        {
            if (wrappedConverter == null)
            {
                throw new ArgumentNullException("wrappedConverter");
            }
            if (sourceTypeIsInitialisedProperty == null)
            {
                throw new ArgumentNullException("destTypeIsInitialisedProperty");
            }
            if (sourceTypeIsInitialisedProperty.DeclaringType != typeof(TSource))
            {
                throw new ArgumentException("sourceTypeIsInitialisedProperty's DeclaringType must be TSource");
            }
            if (sourceTypeIsInitialisedProperty.PropertyType != typeof(bool))
            {
                throw new ArgumentException("sourceTypeIsInitialisedProperty's PropertyType must be bool");
            }

            _wrappedConverter = wrappedConverter;
            _sourceTypeIsInitialisedProperty = sourceTypeIsInitialisedProperty;

            var srcParameter = Expression.Parameter(typeof(TSource), "src");

            _converterFuncExpression = Expression.Lambda <Func <TSource, TDest> >(
                GetTypeConverterExpression(srcParameter),
                srcParameter
                );

            _converter = _converterFuncExpression.Compile();
        }
        private static ProjectionCacheEntry CreateProjectionDataWithinAcquiredConverterCacheLock <TSource, TInterim, TDest>(
            ICompilableTypeConverter <TSource, TDest> sourceToDestConverter,
            PropertyInfo interimTypeIsInitialisedFlag)
        {
            if (sourceToDestConverter == null)
            {
                throw new ArgumentNullException("sourceToDestConverter");
            }
            if (interimTypeIsInitialisedFlag == null)
            {
                throw new ArgumentNullException("interimTypeIsInitialisedFlag");
            }
            if (interimTypeIsInitialisedFlag.DeclaringType != typeof(TInterim))
            {
                throw new ArgumentException("interimTypeIsInitialisedFlag's DeclaringType must be TInterim");
            }

            // Generate a source:interim converter, if the source value is null then an interim type with false is-initialised flag will be generated,
            // otherwise a fully-populate interim instance with is-initialised flag set to true will result (this is because the _converter instance
            // is configured with the CreateEmptyInstanceWithDefaultPropertyValues option).
            var sourceToInterimConverter = _converter.GetConverter <TSource, TInterim>(
                new PropertyInfo[0],                    // propertiesToIgnoreIfSettingPropertiesOnTDest,
                new[] { interimTypeIsInitialisedFlag }, // initialisedFlagsIfTranslatingNullsToEmptyInstances,
                ConverterOverrideBehaviourOptions.UseAnyExistingConverter
                );

            // Generate an interim:dest converter. This is done in two steps, first a basic interim:dest converter is initialised using the _converter,
            // then this needs wrapping in an UninitialisedSourceToNullHandlingConverter which re-inserts the logic around the interim type's is-
            // initialised flag; if the input is an interim type instance with is-initialised flag set to false, then the result should be null
            var interimToDestConverter = new UninitialisedSourceToNullHandlingConverter <TInterim, TDest>(
                _converter.GetConverter <TInterim, TDest>(
                    new PropertyInfo[0],                     // propertiesToIgnoreIfSettingPropertiesOnTDest,
                    new PropertyInfo[0],                     // initialisedFlagsIfTranslatingNullsToEmptyInstances,
                    ConverterOverrideBehaviourOptions.UseAnyExistingConverter
                    ),
                interimTypeIsInitialisedFlag
                );

            // This interim:dest converter should override in the wrapped "_converter" that the call to GetConverter above will have generated. This will
            // be important if there are further translations generated where there are properties that required this interim:dest mapping (since, if we
            // don't make this call, then the translation that the wrapped _converter will use won't know to set the is-initialised flag correctly).
            _converter.SetConverter <TInterim, TDest>(interimToDestConverter);

            return(new ProjectionCacheEntry(
                       typeof(TSource),
                       typeof(TDest),
                       typeof(TInterim),
                       sourceToInterimConverter,
                       interimToDestConverter
                       ));
        }
        public CompilableTypeConverterPropertyGetterFactory(INameMatcher nameMatcher, ICompilableTypeConverter <TPropertyOnSource, TPropertyAsRetrieved> typeConverter)
        {
            if (nameMatcher == null)
            {
                throw new ArgumentNullException("nameMatcher");
            }
            if (typeConverter == null)
            {
                throw new ArgumentNullException("typeConverter");
            }

            _nameMatcher   = nameMatcher;
            _typeConverter = typeConverter;
        }
                public Projection(
                    ICompilableTypeConverter <TSource, TInterim> sourceTypeToInterimTypeConversion,
                    ICompilableTypeConverter <TInterim, TDest> interimTypeToDestTypeConversion)
                {
                    if (sourceTypeToInterimTypeConversion == null)
                    {
                        throw new ArgumentNullException("sourceTypeToInterimTypeConversion");
                    }
                    if (interimTypeToDestTypeConversion == null)
                    {
                        throw new ArgumentNullException("interimTypeToDestTypeConversion");
                    }

                    _sourceTypeToInterimTypeConversion = sourceTypeToInterimTypeConversion;
                    _interimTypeToDestTypeConversion   = interimTypeToDestTypeConversion;
                }
        /// <summary>
        /// Specify a converter that will used whenever either a TSource-to-TDest translation is requested or a translation where properties must
        /// be translated from TSource to TDest (or from IEnumerable sets of TSource to TDest). Any converter that was previously available for
        /// this translation will be superceded by the one specified here (subsequent calls to this method with the same TSource and TDest
        /// will then take precedence again).
        /// </summary>
        public void SetConverter <TSource, TDest>(ICompilableTypeConverter <TSource, TDest> converter)
        {
            if (converter == null)
            {
                throw new ArgumentNullException("converter");
            }

            // For the ExtendableCompilableTypeConverterFactories, we just call AddNewConverter which will register the new converter before
            // any other converters which may handle the same translation. This sidesteps any complicated logic that might be involved in
            // trying to identify any converters from its repertoire that may need to be removed, this way the new converter will just
            // take precedence and any others will be ignored.
            _constructorBasedConverterFactory    = _constructorBasedConverterFactory.AddNewConverter <TSource, TDest>(converter);
            _propertySetterBasedConverterFactory = _propertySetterBasedConverterFactory.AddNewConverter <TSource, TDest>(converter);

            // For the internal cache (which will handle requests for translations of TSource-to-TDest, as opposed to translations which
            // require property retrieval from TSource to populate a property of constructor argument of TDest), we just set the value
            // on the dictionary, overwriting anything there before or adding a new item if not overwriting anything pre-existing.
            _converterCache[Tuple.Create(typeof(TSource), typeof(TDest))] = converter;
        }
예제 #6
0
        public EnumerableCompilablePropertyGetterFactory(
            INameMatcher nameMatcher,
            ICompilableTypeConverter <TPropertyOnSourceElement, TPropertyAsRetrievedElement> typeConverter,
            EnumerableSetNullHandlingOptions enumerableSetNullHandling)
        {
            if (nameMatcher == null)
            {
                throw new ArgumentNullException("nameMatcher");
            }
            if (typeConverter == null)
            {
                throw new ArgumentNullException("typeConverter");
            }
            if (!Enum.IsDefined(typeof(EnumerableSetNullHandlingOptions), enumerableSetNullHandling))
            {
                throw new ArgumentOutOfRangeException("enumerableSetNullHandling");
            }

            _nameMatcher               = nameMatcher;
            _typeConverter             = typeConverter;
            _enumerableSetNullHandling = enumerableSetNullHandling;
        }
        public CompilableTypeConverterPropertyGetter(PropertyInfo propertyInfo, ICompilableTypeConverter <TPropertyOnSource, TPropertyAsRetrieved> compilableTypeConverter)
        {
            if (propertyInfo == null)
            {
                throw new ArgumentNullException("propertyInfo");
            }
            if (!typeof(TSourceObject).HasProperty(propertyInfo))
            {
                throw new ArgumentException("Invalid propertyInfo, not available on type TSource");
            }
            if (!propertyInfo.PropertyType.Equals(typeof(TPropertyOnSource)))
            {
                throw new ArgumentException("Invalid propertyInfo - PropertyType must match TPropertyOnSource");
            }
            if (compilableTypeConverter == null)
            {
                throw new ArgumentNullException("compilableTypeConverter");
            }

            _propertyInfo            = propertyInfo;
            _compilableTypeConverter = compilableTypeConverter;
        }
        public EnumerableCompilablePropertyGetter(
            PropertyInfo propertyInfo,
            ICompilableTypeConverter <TPropertyOnSourceElement, TPropertyAsRetrievedElement> typeConverter,
            EnumerableSetNullHandlingOptions enumerableSetNullHandling)
        {
            // When checking types here, we're effectively only allowing equality - not IsAssignableFrom - of the elements of the IEnumerable data (since IEnumerable<B>
            // is not assignable to IEnumerable<A> even if B is derived from / implements A), this is desirable to ensure that the most appropriate property getter
            // ends up getting matched
            if (propertyInfo == null)
            {
                throw new ArgumentNullException("propertyInfo");
            }
            if (!typeof(TSourceObject).HasProperty(propertyInfo))
            {
                throw new ArgumentException("Invalid propertyInfo, not available on type TSource");
            }
            if (!typeof(IEnumerable <TPropertyOnSourceElement>).IsAssignableFrom(propertyInfo.PropertyType))
            {
                throw new ArgumentException("Invalid propertyInfo - its PropertyType must be assignable match to IEnumerable<TPropertyOnSourceElement>");
            }
            if (!typeof(IEnumerable <TPropertyAsRetrievedElement>).IsAssignableFrom(typeof(TPropertyAsRetrieved)))
            {
                throw new ArgumentException("Invalid configuration - TPropertyAsRetrieved must be assignable to IEnumerable<TPropertyAsRetrievedElement>");
            }
            if (typeConverter == null)
            {
                throw new ArgumentNullException("typeConverter");
            }
            if (!Enum.IsDefined(typeof(EnumerableSetNullHandlingOptions), enumerableSetNullHandling))
            {
                throw new ArgumentOutOfRangeException("enumerableSetNullHandling");
            }

            _propertyInfo             = propertyInfo;
            _typeConverter            = typeConverter;
            EnumerableSetNullHandling = enumerableSetNullHandling;
        }
            /// <summary>
            /// This must never return null nor may any null entries be in the returned set. It will never be called with a null nameMatcher or converter reference.
            /// </summary>
            public IEnumerable <ICompilablePropertyGetterFactory> Get <TSource, TDest>(ICompilableTypeConverter <TSource, TDest> converter)
            {
                if (converter == null)
                {
                    throw new ArgumentNullException("converter");
                }

                return(new ICompilablePropertyGetterFactory[]
                {
                    new EnumerableCompilablePropertyGetterFactory <TSource, TDest>(
                        _nameMatcher,
                        converter,
                        _enumerableSetNullHandling
                        )
                });
            }
        /// <summary>
        /// Generate a further extended converter factory that will be able to handle conversion of instances of TSourceNew as well as IEnumerable / Lists
        /// of them. This will never return null.
        /// </summary>
        public ExtendableCompilableTypeConverterFactory AddNewConverter <TSource, TDest>(ICompilableTypeConverter <TSource, TDest> converterNew)
        {
            if (converterNew == null)
            {
                throw new ArgumentNullException("converterNew");
            }

            // Get any additional, extrapolated property getter factories (ensure that neither null nor a set containing nulls is generated)
            var extrapolatedPropertyGetterFactories = _configurationData.PropertyGetterFactoryExtrapolator.Get <TSource, TDest>(converterNew);

            if (extrapolatedPropertyGetterFactories == null)
            {
                throw new Exception("propertyGetterFactoryExtrapolator (" + _configurationData.PropertyGetterFactoryExtrapolator.GetType().ToString() + ") returned null");
            }
            var extrapolatedPropertyGetterFactoriesList = new List <ICompilablePropertyGetterFactory>(extrapolatedPropertyGetterFactories);

            if (extrapolatedPropertyGetterFactoriesList.Any(f => f == null))
            {
                throw new Exception("propertyGetterFactoryExtrapolator (" + _configurationData.PropertyGetterFactoryExtrapolator.GetType().ToString() + ") returned a null reference in the set");
            }

            // Create a property getter factory that retrieves and convert properties using this converter by default, combine with any additional factories
            // generated by the propertyGetterFactoryExtrapolator. Note: The new property getter factories are specified first in the list so if there are
            // any other factories which could retrieve data for the same types, the new ones will take precedence (the logic being that the new ones
            // were most recently specified and so are more likely to be expected to be the ones that will do the work, given the chance)
            var extendedPropertyGetterFactories = new List <ICompilablePropertyGetterFactory>();

            extendedPropertyGetterFactories.Add(
                new CompilableTypeConverterPropertyGetterFactory <TSource, TDest>(
                    _configurationData.NameMatcher,
                    converterNew
                    )
                );
            extendedPropertyGetterFactories.AddRange(extrapolatedPropertyGetterFactoriesList);
            extendedPropertyGetterFactories.AddRange(_configurationData.BasePropertyGetterFactories);

            // Return a new ExtendableCompilableTypeConverterFactory that can make use of these new property getter factories
            return(new ExtendableCompilableTypeConverterFactory(
                       _configurationData.NameMatcher,
                       extendedPropertyGetterFactories,
                       _configurationData.ConverterFactoryGenerator,
                       _configurationData.PropertyGetterFactoryExtrapolator
                       ));
        }