private object InvokeNonVoidFunc( object func, object[] arguments, Type returnType ) { var invokeMethod = func.GetType().GetMethod(nameof(Func <int> .Invoke)); var result = invokeMethod?.Invoke(func, arguments); if (returnType is null) { return(null); } if (result is null) { return(returnType.IsNullableType() ? null : returnType.DefaultValue()); } var resultType = result.GetType(); if (resultType == returnType) { return(result); } var converter = ConverterLocator.GetConverter(resultType, returnType); return(converter?.Convert(result) ?? throw new InvalidOperationException( $"Can't convert result from {resultType} to {returnType}" )); }
/// <summary> /// Attempts to set the value of the named property /// </summary> /// <param name="propertyName">Name of the property to set</param> /// <param name="newValue">Value to set. The value may be converted to match the underlying type when required.</param> public void SetPropertyValue(string propertyName, object newValue) { // TODO: find the correct dictionary to work with for this propertyName var data = _data[0]; CheckPropertyExists(propertyName); var mimickedProperty = GetMimickedProperty(propertyName); var newValueType = newValue?.GetType(); if (newValueType == null) { SetDefaultValueForType(data, propertyName, mimickedProperty); } else if (mimickedProperty.PropertyType.IsAssignableFrom(newValueType)) { data[propertyName] = newValue; } else { var converter = ConverterLocator.GetConverter(newValueType, mimickedProperty.PropertyType); if (converter == null) { SetDefaultValueForType(data, propertyName, mimickedProperty); } data[propertyName] = ConvertWith(converter, newValue, mimickedProperty.PropertyType); } }
private object DuckIfRequired(PropertyInfoCacheItem propertyInfoCacheItem, string propertyName) { if (_shimmedProperties.TryGetValue(propertyName, out var existingShim)) { return(existingShim); } var getter = propertyInfoCacheItem.Getter; var propValue = getter(); var correctType = _localMimickPropertyInfos[propertyName].PropertyType; if (propValue == null) { return(GetDefaultValueFor(correctType)); } var propValueType = propertyInfoCacheItem.PropertyInfo.PropertyType; if (correctType.IsAssignableFrom(propValueType)) { return(propValue); } var converter = ConverterLocator.GetConverter(propValueType, correctType); if (converter != null) { return(ConvertWith(converter, propValue, correctType)); } if (EnumConverter.TryConvert(propValueType, correctType, propValue, out var result)) { return(result); } if (correctType.ShouldTreatAsPrimitive()) { return(GetDefaultValueFor(correctType)); } if (CannotShim(propertyName, propValue, correctType)) { return(null); } var duckType = MakeTypeToImplement(correctType, _isFuzzy); var asDict = propValue.TryConvertToDictionary(); var instance = Activator.CreateInstance(duckType, asDict == null // ReSharper disable once RedundantExplicitArrayCreation ? new object[] { new object[] { propValue } } : new object[] { asDict }); _shimmedProperties[propertyName] = instance; return(instance); }
/// <summary> /// Gets the value of a property by name /// </summary> /// <param name="propertyName">Name of the property to get the value of</param> /// <returns>The value of the property, where possible. /// May return the default value for the property type when it is not found /// and may attempt automatic conversion when the type to represent does not /// match the underlying type</returns> public object GetPropertyValue(string propertyName) { // TODO: examine all dictionaries, or at least, the correct one var data = _data[0]; CheckPropertyExists(propertyName); if (_shimmedProperties.TryGetValue(propertyName, out var propValue)) { return(propValue); } var mimickedProperty = GetMimickedProperty(propertyName); var key = _isFuzzy ? FuzzyFindKeyFor(propertyName) ?? propertyName : propertyName; if (!data.TryGetValue(key, out propValue)) { return(GetDefaultValueFor(mimickedProperty.PropertyType)); } if (propValue is null) { return(TryResolveNullValueFOr(mimickedProperty)); } // ReSharper disable once UseMethodIsInstanceOfType var propType = propValue.GetType(); if (mimickedProperty.PropertyType.IsAssignableFrom(propType)) { return(propValue); } var converter = ConverterLocator.GetConverter(propType, mimickedProperty.PropertyType); if (converter != null) { return(ConvertWith(converter, propValue, mimickedProperty.PropertyType)); } return(EnumConverter.TryConvert(propType, mimickedProperty.PropertyType, propValue, out var result) ? result : GetDefaultValueFor(mimickedProperty.PropertyType)); }
public void GetConverterFor_GivenIntAndString_ShouldReturnConverter() { //--------------- Arrange ------------------- //--------------- Assume ---------------- //--------------- Act ---------------------- var result1 = ConverterLocator.GetConverter(typeof(int), typeof(string)); var result2 = ConverterLocator.GetConverter(typeof(string), typeof(int)); //--------------- Assert ----------------------- Expect(result1).Not.To.Be.Null(); Expect(result2).Not.To.Be.Null(); Expect(result1).To.Equal(result2); var useful2 = result1 as IConverter <string, int>; Expect(useful2).Not.To.Be.Null(); }
private void TrySetValue(object newValue, Type newValueType, PropertyInfoCacheItem propInfo) { var pType = propInfo.PropertyInfo.PropertyType; var setter = propInfo.Setter; if (pType.IsAssignableFrom(newValueType)) { setter(newValue); return; } var converter = ConverterLocator.GetConverter(newValueType, pType); if (converter == null) { throw new InvalidOperationException( $"Unable to set property: no converter for {newValueType.Name} => {pType.Name}"); } var converted = ConvertWith(converter, newValue, pType); setter(converted); }
internal static T InternalDuckAs <T>( this object src, bool allowFuzzy, bool throwOnError ) where T : class { if (src == null) { return(null); } var converter = ConverterLocator.GetConverter(src.GetType(), typeof(T)); if (converter != null) { return((T)converter.Convert(src)); } if (!InternalCanDuckAs <T>(src, allowFuzzy, throwOnError)) { return(null); } var srcAsDict = TryConvertToDictionary(src); if (allowFuzzy) { srcAsDict = srcAsDict?.ToCaseInsensitiveDictionary(); } var duckType = FindOrCreateDuckTypeFor <T>(allowFuzzy); // ReSharper disable RedundantExplicitArrayCreation var ctorArgs = srcAsDict == null ? new object[] { new object[] { src } } : new object[] { new IDictionary <string, object>[] { srcAsDict } }; // ReSharper restore RedundantExplicitArrayCreation return((T)Activator.CreateInstance(duckType, ctorArgs)); }
private object[] PrepareArguments( object[] arguments, Type[] parameterTypes) { return(arguments.Select((arg, idx) => { var argType = arg?.GetType(); if (arg is null || arg.GetType() == parameterTypes[idx]) { return arg; } if (parameterTypes[idx].IsAssignableFrom(argType)) { return arg; } var converter = ConverterLocator.GetConverter(argType, parameterTypes[idx]); return converter.Convert(arg); }).ToArray()); }
internal static bool InternalCanDuckAs( Type type, Type toType, bool allowFuzzy, // ReSharper disable once UnusedParameter.Global // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Global bool throwIfNotAllowed ) { if (ConverterLocator.HaveConverterFor(type, toType)) { return(true); } var errors = GetDuckErrorsFor(type, toType, allowFuzzy); if (throwIfNotAllowed && errors.Any()) { throw new UnDuckableException(errors); } return(!errors.Any()); }
/// <summary> /// Attempts to set the value of the named property /// </summary> /// <param name="propertyName">Name of the property to set</param> /// <param name="newValue">Value to set. The value may be converted to match the underlying type when required.</param> public void SetPropertyValue(string propertyName, object newValue) { CheckPropertyExists(propertyName); var mimickedProperty = GetMimickedProperty(propertyName); var newValueType = newValue?.GetType(); if (newValueType == null) { SetDefaultValueForType(_data, propertyName, mimickedProperty); } else if (mimickedProperty.PropertyType.IsAssignableFrom(newValueType)) { _data[propertyName] = newValue; } else { var converter = ConverterLocator.GetConverter( newValueType, mimickedProperty.PropertyType ); if (converter is null) { SetDefaultValueForType( _data, propertyName, mimickedProperty ); return; } _data[propertyName] = ConvertWith( converter, newValue, mimickedProperty.PropertyType ); } }
private static bool MatchesTypeOrCanConvert(PropertyInfo needle, PropertyInfo matchByName) { return(matchByName.PropertyType == needle.PropertyType || ConverterLocator.HaveConverterFor(matchByName.PropertyType, needle.PropertyType) || EnumConverter.CanPerhapsConvertBetween(matchByName.PropertyType, needle.PropertyType)); }
// TODO: should be moved out into a shared location & used at duck-type // to prevent erroneous ducks private bool NonVoidFunctionAccepts( object value, object[] arguments, out Type[] parameterTypes, out Type returnType ) { parameterTypes = null; returnType = null; var funcType = value.GetType(); if (!funcType.IsGenericType) { return(false); } var parameterCount = Array.IndexOf(FuncGenerics, funcType.GetGenericTypeDefinition()); if (parameterCount != arguments.Length) { if (parameterCount > FuncGenerics.Length) { throw new NotSupportedException( $"methods with more than {FuncGenerics.Length} parameters are not supported"); } return(false); } var genericParameters = funcType.GetGenericArguments(); parameterTypes = genericParameters.Take(genericParameters.Length - 1).ToArray(); returnType = genericParameters.Last(); var zipped = arguments.Zip( parameterTypes, (argument, parameterType) => new { argumentType = argument?.GetType(), parameterType } ); return(zipped.Aggregate( true, (acc, cur) => { if (!acc) { return false; } if (cur.argumentType is null && cur.parameterType.IsNullableType()) { return true; } if (cur.argumentType.IsAssignableOrUpCastableTo(cur.parameterType)) { return true; } return cur.argumentType == cur.parameterType || ConverterLocator.HaveConverterFor(cur.argumentType, cur.parameterType); }));
private static bool CanAutoConvert(Type srcType, Type targetType) { return(ConverterLocator.GetConverter(srcType, targetType) != null); }