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);
            }
        }
Beispiel #3
0
        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();
        }
Beispiel #6
0
        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
                    );
            }
        }
Beispiel #11
0
 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);
 }