private object?ConvertMultiple( IMemberSchema memberSchema, IReadOnlyList <string> rawValues, Type targetEnumerableType, Type targetElementType) { var array = rawValues .Select(v => ConvertSingle(memberSchema, v, targetElementType)) .ToNonGenericArray(targetElementType); var arrayType = array.GetType(); // Assignable from an array (T[], IReadOnlyList<T>, etc) if (targetEnumerableType.IsAssignableFrom(arrayType)) { return(array); } // Array-constructible (List<T>, HashSet<T>, etc) var arrayConstructor = targetEnumerableType.GetConstructor(new[] { arrayType }); if (arrayConstructor is not null) { return(arrayConstructor.Invoke(new object?[] { array })); } throw CliFxException.InternalError( $"{memberSchema.GetKind()} {memberSchema.GetFormattedIdentifier()} has an unsupported underlying property type." + Environment.NewLine + $"There is no known way to convert an array of `{targetElementType.FullName}` into an instance of type `{targetEnumerableType.FullName}`." + Environment.NewLine + "To fix this, change the property to use a type which can be assigned from an array or a type that has a constructor which accepts an array." ); }
/// <inheritdoc /> public object CreateInstance(Type type) { try { return(Activator.CreateInstance(type)); } catch (Exception ex) { throw CliFxException.InternalError( $"Failed to create an instance of type `{type.FullName}`." + Environment.NewLine + "Default type activator is only capable of instantiating a type if it has a public parameterless constructor." + Environment.NewLine + "To fix this, either add a parameterless constructor to the type or configure a custom activator on the application.", ex ); } }
private object?ConvertSingle(IMemberSchema memberSchema, string?rawValue, Type targetType) { // Custom converter if (memberSchema.ConverterType is not null) { var converter = (IBindingConverter)_typeActivator.CreateInstance(memberSchema.ConverterType); return(converter.Convert(rawValue)); } // Assignable from string (e.g. string itself, object, etc) if (targetType.IsAssignableFrom(typeof(string))) { return(rawValue); } // Special case for bool if (targetType == typeof(bool)) { return(string.IsNullOrWhiteSpace(rawValue) || bool.Parse(rawValue)); } // Special case for DateTimeOffset if (targetType == typeof(DateTimeOffset)) { return(DateTimeOffset.Parse(rawValue, _formatProvider)); } // Special case for TimeSpan if (targetType == typeof(TimeSpan)) { return(TimeSpan.Parse(rawValue, _formatProvider)); } // Enum if (targetType.IsEnum) { // Null reference exception will be handled upstream return(Enum.Parse(targetType, rawValue !, true)); } // Convertible primitives (int, double, char, etc) if (targetType.Implements(typeof(IConvertible))) { return(Convert.ChangeType(rawValue, targetType, _formatProvider)); } // Nullable<T> var nullableUnderlyingType = targetType.TryGetNullableUnderlyingType(); if (nullableUnderlyingType is not null) { return(!string.IsNullOrWhiteSpace(rawValue) ? ConvertSingle(memberSchema, rawValue, nullableUnderlyingType) : null); } // String-constructible (FileInfo, etc) var stringConstructor = targetType.GetConstructor(new[] { typeof(string) }); if (stringConstructor is not null) { return(stringConstructor.Invoke(new object?[] { rawValue })); } // String-parseable (with IFormatProvider) var parseMethodWithFormatProvider = targetType.TryGetStaticParseMethod(true); if (parseMethodWithFormatProvider is not null) { return(parseMethodWithFormatProvider.Invoke(null, new object?[] { rawValue, _formatProvider })); } // String-parseable (without IFormatProvider) var parseMethod = targetType.TryGetStaticParseMethod(); if (parseMethod is not null) { return(parseMethod.Invoke(null, new object?[] { rawValue })); } throw CliFxException.InternalError( $"{memberSchema.GetKind()} {memberSchema.GetFormattedIdentifier()} has an unsupported underlying property type." + Environment.NewLine + $"There is no known way to convert a string value into an instance of type `{targetType.FullName}`." + Environment.NewLine + "To fix this, either change the property to use a supported type or configure a custom converter." ); }