BadScript 2
Loading...
Searching...
No Matches
TypeConverter.cs
Go to the documentation of this file.
1// Copyright 2005-2015 Giacomo Stelluti Scala & Contributors. All rights reserved. See License.md in the project root for license information.
2
3using System;
4using System.Collections.Generic;
5using System.Globalization;
6using System.Linq;
7using System.Reflection;
8
10
11using CSharpx;
12
14
15namespace CommandLine.Core
16{
17 internal static class TypeConverter
18 {
19 public static Maybe<object> ChangeType(IEnumerable<string> values,
20 Type conversionType,
21 bool scalar,
22 bool isFlag,
23 CultureInfo conversionCulture,
24 bool ignoreValueCase)
25 {
26 return isFlag ? ChangeTypeFlagCounter(values, conversionType, conversionCulture, ignoreValueCase) :
27 scalar ? ChangeTypeScalar(values.Last(), conversionType, conversionCulture, ignoreValueCase) :
28 ChangeTypeSequence(values, conversionType, conversionCulture, ignoreValueCase);
29 }
30
31 private static Maybe<object> ChangeTypeSequence(IEnumerable<string> values,
32 Type conversionType,
33 CultureInfo conversionCulture,
34 bool ignoreValueCase)
35 {
36 Type type =
37 conversionType.GetTypeInfo()
38 .GetGenericArguments()
39 .SingleOrDefault()
40 .ToMaybe()
41 .FromJustOrFail(new
42 InvalidOperationException("Non scalar properties should be sequence of type IEnumerable<T>."
43 )
44 );
45
46 IEnumerable<Maybe<object>> converted =
47 values.Select(value => ChangeTypeScalar(value, type, conversionCulture, ignoreValueCase));
48
49 return converted.Any(a => a.MatchNothing())
50 ? Maybe.Nothing<object>()
51 : Maybe.Just(converted.Select(c => ((Just<object>)c).Value)
52 .ToUntypedArray(type)
53 );
54 }
55
56 private static Maybe<object> ChangeTypeScalar(string value,
57 Type conversionType,
58 CultureInfo conversionCulture,
59 bool ignoreValueCase)
60 {
62 ChangeTypeScalarImpl(value, conversionType, conversionCulture, ignoreValueCase);
63
64 result.Match((_, __) => { },
65 e => e.First()
66 .RethrowWhenAbsentIn(new[]
67 {
68 typeof(InvalidCastException),
69 typeof(FormatException),
70 typeof(OverflowException),
71 }
72 )
73 );
74
75 return result.ToMaybe();
76 }
77
78 private static Maybe<object> ChangeTypeFlagCounter(IEnumerable<string> values,
79 Type conversionType,
80 CultureInfo conversionCulture,
81 bool ignoreValueCase)
82 {
83 IEnumerable<Maybe<object>> converted =
84 values.Select(value => ChangeTypeScalar(value, typeof(bool), conversionCulture, ignoreValueCase));
85
86 return converted.Any(maybe => maybe.MatchNothing())
87 ? Maybe.Nothing<object>()
88 : Maybe.Just((object)converted.Count(value => value.IsJust()));
89 }
90
91 private static object ConvertString(string value, Type type, CultureInfo conversionCulture)
92 {
93 try
94 {
95 return Convert.ChangeType(value, type, conversionCulture);
96 }
97 catch (InvalidCastException)
98 {
99 // Required for converting from string to TimeSpan because Convert.ChangeType can't
100 return System.ComponentModel.TypeDescriptor.GetConverter(type)
101 .ConvertFrom(null, conversionCulture, value);
102 }
103 }
104
106 Type conversionType,
107 CultureInfo conversionCulture,
108 bool ignoreValueCase)
109 {
110 Func<object> changeType = () =>
111 {
112 Func<object> safeChangeType = () =>
113 {
114 bool isFsOption = ReflectionHelper.IsFSharpOptionType(conversionType);
115
116 Func<Type> getUnderlyingType =
117 () =>
118#if !SKIP_FSHARP
119 isFsOption
120 ? FSharpOptionHelper.GetUnderlyingType(conversionType) :
121#endif
122 Nullable.GetUnderlyingType(conversionType);
123
124 Type type = getUnderlyingType() ?? conversionType;
125
126 Func<object> withValue =
127 () =>
128#if !SKIP_FSHARP
129 isFsOption
130 ? FSharpOptionHelper.Some(type, ConvertString(value, type, conversionCulture)) :
131#endif
132 ConvertString(value, type, conversionCulture);
133#if !SKIP_FSHARP
134 Func<object> empty = () => isFsOption ? FSharpOptionHelper.None(type) : null;
135#else
136 Func<object> empty = () => null;
137#endif
138
139 return value == null ? empty() : withValue();
140 };
141
142 return value.IsBooleanString() && conversionType == typeof(bool) ? value.ToBoolean() :
143 conversionType.GetTypeInfo()
144 .IsEnum ? value.ToEnum(conversionType, ignoreValueCase) : safeChangeType();
145 };
146
147 Func<object> makeType = () =>
148 {
149 try
150 {
151 ConstructorInfo ctor = conversionType.GetTypeInfo()
152 .GetConstructor(new[] { typeof(string) });
153
154 return ctor.Invoke(new object[] { value });
155 }
156 catch (Exception)
157 {
158 throw new
159 FormatException("Destination conversion type must have a constructor that accepts a string.");
160 }
161 };
162
163 if (conversionType.IsCustomStruct())
164 {
165 return Result.Try(makeType);
166 }
167
168 return Result.Try(conversionType.IsPrimitiveEx() || ReflectionHelper.IsFSharpOptionType(conversionType)
169 ? changeType
170 : makeType
171 );
172 }
173
174 private static object ToEnum(this string value, Type conversionType, bool ignoreValueCase)
175 {
176 object parsedValue;
177
178 try
179 {
180 parsedValue = Enum.Parse(conversionType, value, ignoreValueCase);
181 }
182 catch (ArgumentException)
183 {
184 throw new FormatException();
185 }
186
187 if (IsDefinedEx(parsedValue))
188 {
189 return parsedValue;
190 }
191
192 throw new FormatException();
193 }
194
195 private static bool IsDefinedEx(object enumValue)
196 {
197 char firstChar = enumValue.ToString()[0];
198
199 if (char.IsDigit(firstChar) || firstChar == '-')
200 {
201 return false;
202 }
203
204 return true;
205 }
206 }
207}
Models a CSharpx.Maybe when contains a value.
Definition Maybe.cs:88
The Maybe type models an optional value. A value of type Maybe a either contains a value of type a (r...
Definition Maybe.cs:33
static bool IsDefinedEx(object enumValue)
static object ToEnum(this string value, Type conversionType, bool ignoreValueCase)
static Maybe< object > ChangeTypeSequence(IEnumerable< string > values, Type conversionType, CultureInfo conversionCulture, bool ignoreValueCase)
static Result< object, Exception > ChangeTypeScalarImpl(string value, Type conversionType, CultureInfo conversionCulture, bool ignoreValueCase)
static Maybe< object > ChangeTypeScalar(string value, Type conversionType, CultureInfo conversionCulture, bool ignoreValueCase)
static Maybe< object > ChangeTypeFlagCounter(IEnumerable< string > values, Type conversionType, CultureInfo conversionCulture, bool ignoreValueCase)
static object ConvertString(string value, Type type, CultureInfo conversionCulture)
static Maybe< object > ChangeType(IEnumerable< string > values, Type conversionType, bool scalar, bool isFlag, CultureInfo conversionCulture, bool ignoreValueCase)
static object Some(Type type, object value)
Represents the result of a computation.