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; }
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 )); }