Esempio n. 1
0
    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."
                  );
    }
Esempio n. 2
0
 /// <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
                   );
     }
 }
Esempio n. 3
0
    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."
                  );
    }