@@ -70,7 +70,6 @@ public override Expression GetConversion(Expression sourceValue, Type targetEnum
7070 return GetStringValueConversion (
7171 sourceValue ,
7272 fallbackValue ,
73- nonNullableSourceType ,
7473 nonNullableTargetEnumType ) ;
7574 }
7675
@@ -85,7 +84,7 @@ private Expression GetFlagsEnumConversion(
8584
8685 var enumValueVariable = Expression . Variable ( underlyingEnumType , enumTypeName + "Value" ) ;
8786 var underlyingTypeDefault = underlyingEnumType . ToDefaultExpression ( ) ;
88- var assignEnumValue = Expression . Assign ( enumValueVariable , underlyingTypeDefault ) ;
87+ var assignEnumValue = enumValueVariable . AssignTo ( underlyingTypeDefault ) ;
8988
9089 if ( nonNullableSourceType . IsNumeric ( ) )
9190 {
@@ -118,13 +117,14 @@ private Expression GetFlagsEnumConversion(
118117 var enumeratorCurrent = Expression . Property ( sourceValuesVariable , "Current" ) ;
119118 var stringTrimMethod = typeof ( string ) . GetPublicInstanceMethod ( "Trim" , parameterCount : 0 ) ;
120119 var currentTrimmed = Expression . Call ( enumeratorCurrent , stringTrimMethod ) ;
121- var assignLocalVariable = Expression . Assign ( localSourceValueVariable , currentTrimmed ) ;
120+ var assignLocalVariable = localSourceValueVariable . AssignTo ( currentTrimmed ) ;
122121
123- var numericTryParseCall = GetNumericTryParseCall (
124- enumTypeName ,
125- underlyingEnumType ,
126- localSourceValueVariable ,
127- out var sourceNumericValueVariable ) ;
122+ var isNumericTest = GetIsNumericTest ( localSourceValueVariable ) ;
123+
124+ var sourceNumericValueVariableName = enumTypeName + underlyingEnumType . Name + "Value" ;
125+ var sourceNumericValueVariable = Expression . Variable ( underlyingEnumType , sourceNumericValueVariableName ) ;
126+ var parsedString = GetStringParseCall ( localSourceValueVariable , underlyingEnumType ) ;
127+ var assignNumericVariable = sourceNumericValueVariable . AssignTo ( parsedString ) ;
128128
129129 var numericValuePopulationLoop = GetNumericToFlagsEnumPopulationLoop (
130130 nonNullableTargetEnumType ,
@@ -136,6 +136,7 @@ private Expression GetFlagsEnumConversion(
136136
137137 var numericValuePopulationBlock = Expression . Block (
138138 new [ ] { enumValuesVariable } ,
139+ assignNumericVariable ,
139140 assignEnumValues ,
140141 numericValuePopulationLoop ) ;
141142
@@ -147,7 +148,7 @@ private Expression GetFlagsEnumConversion(
147148 var assignParsedEnumValue = Expression . OrAssign ( enumValueVariable , stringValueConversion ) ;
148149
149150 var assignValidValuesIfPossible = Expression . IfThenElse (
150- numericTryParseCall ,
151+ isNumericTest ,
151152 numericValuePopulationBlock ,
152153 assignParsedEnumValue ) ;
153154
@@ -187,7 +188,7 @@ private static Expression GetNumericToFlagsEnumConversion(
187188 sourceValue = Expression . Convert ( sourceValue , underlyingEnumType ) ;
188189 }
189190
190- var assignSourceVariable = Expression . Assign ( sourceValueVariable , sourceValue ) ;
191+ var assignSourceVariable = sourceValueVariable . AssignTo ( sourceValue ) ;
191192
192193 var populationLoop = GetNumericToFlagsEnumPopulationLoop (
193194 nonNullableTargetEnumType ,
@@ -227,7 +228,7 @@ private static Expression GetNumericToFlagsEnumPopulationLoop(
227228
228229 var localEnumValueVariable = Expression . Variable ( underlyingEnumType , enumTypeName ) ;
229230 var enumeratorCurrent = Expression . Property ( enumValuesVariable , "Current" ) ;
230- var assignLocalVariable = Expression . Assign ( localEnumValueVariable , enumeratorCurrent ) ;
231+ var assignLocalVariable = localEnumValueVariable . AssignTo ( enumeratorCurrent ) ;
231232
232233 var localVariableAndSourceValue = Expression . And ( localEnumValueVariable , sourceValueVariable ) ;
233234 var andResultEqualsEnumValue = Expression . Equal ( localVariableAndSourceValue , localEnumValueVariable ) ;
@@ -298,21 +299,19 @@ private static Expression GetLoopExitCheck(
298299 return Expression . IfThen ( Expression . Not ( enumeratorMoveNext ) , Expression . Break ( loopBreakTarget ) ) ;
299300 }
300301
301- private static Expression GetNumericTryParseCall (
302- string enumTypeName ,
303- Type underlyingEnumType ,
304- Expression stringValue ,
305- out ParameterExpression numericValueVariable )
302+ private static Expression GetIsNumericTest ( Expression stringValue )
306303 {
307- var tryParseMethod = underlyingEnumType
308- . GetPublicStaticMethod ( "TryParse" , parameterCount : 2 ) ;
309-
310- var sourceNumericValueVariableName = enumTypeName + underlyingEnumType . Name + "Value" ;
311- numericValueVariable = Expression . Parameter ( underlyingEnumType , sourceNumericValueVariableName ) ;
312-
313- var tryParseCall = Expression . Call ( tryParseMethod , stringValue , numericValueVariable ) ;
304+ return Expression . Call (
305+ typeof ( char ) . GetPublicStaticMethod ( "IsDigit" , typeof ( string ) , typeof ( int ) ) ,
306+ stringValue ,
307+ 0 . ToConstantExpression ( ) ) ;
308+ }
314309
315- return tryParseCall ;
310+ public static Expression GetStringParseCall ( Expression sourceValue , Type underlyingEnumType )
311+ {
312+ return Expression . Call (
313+ underlyingEnumType . GetPublicStaticMethod ( "Parse" , typeof ( string ) ) ,
314+ sourceValue ) ;
316315 }
317316
318317 private static Expression GetStringToEnumConversion (
@@ -449,9 +448,16 @@ private static Expression GetNumericToEnumConversion(
449448 return nonNullValidValueOrFallback ;
450449 }
451450
452- private static Expression GetIsValidEnumValueCheck ( Type enumType , Expression value )
451+ private static Expression GetIsValidEnumValueCheck (
452+ Type enumType ,
453+ Expression value ,
454+ Expression validEnumValues = null )
453455 {
454- var validEnumValues = GetEnumValuesConstant ( enumType , value . Type ) ;
456+ if ( validEnumValues == null )
457+ {
458+ validEnumValues = GetEnumValuesConstant ( enumType , value . Type ) ;
459+ }
460+
455461 var containsMethod = validEnumValues . Type . GetPublicInstanceMethod ( "Contains" ) ;
456462 var containsCall = Expression . Call ( validEnumValues , containsMethod , value ) ;
457463
@@ -461,7 +467,6 @@ private static Expression GetIsValidEnumValueCheck(Type enumType, Expression val
461467 private Expression GetStringValueConversion (
462468 Expression sourceValue ,
463469 Expression fallbackValue ,
464- Type nonNullableSourceType ,
465470 Type nonNullableTargetEnumType )
466471 {
467472 if ( sourceValue . Type != typeof ( string ) )
@@ -471,29 +476,57 @@ private Expression GetStringValueConversion(
471476
472477 var underlyingEnumType = Enum . GetUnderlyingType ( nonNullableTargetEnumType ) ;
473478
474- var nameMatchingConversion = GetStringToEnumConversion (
479+ var isNumericTest = GetIsNumericTest ( sourceValue ) ;
480+
481+ var numericConversion = GetNumericStringToEnumConversion (
475482 sourceValue ,
476483 fallbackValue ,
477- nonNullableTargetEnumType ) ;
484+ nonNullableTargetEnumType ,
485+ underlyingEnumType ) ;
478486
479- var tryParseCall = GetNumericTryParseCall (
480- GetVariableNameFor ( nonNullableTargetEnumType ) ,
481- underlyingEnumType ,
487+ var nameMatchingConversion = GetStringToEnumConversion (
482488 sourceValue ,
483- out var parseResultVariable ) ;
484-
485- var numericConversion = GetNumericToEnumConversion (
486- parseResultVariable ,
487489 fallbackValue ,
488- nonNullableSourceType ,
489490 nonNullableTargetEnumType ) ;
490491
491492 var numericOrNameConversion = Expression . Condition (
492- tryParseCall ,
493+ isNumericTest ,
493494 numericConversion ,
494495 nameMatchingConversion ) ;
495496
496- return Expression . Block ( new [ ] { parseResultVariable } , numericOrNameConversion ) ;
497+ var valueIsNullOrEmpty = Expression . Call (
498+ typeof ( string ) . GetPublicStaticMethod ( "IsNullOrWhiteSpace" ) ,
499+ sourceValue ) ;
500+
501+ var convertedValueOrDefault = Expression . Condition (
502+ valueIsNullOrEmpty ,
503+ fallbackValue ,
504+ numericOrNameConversion ) ;
505+
506+ return convertedValueOrDefault ;
507+ }
508+
509+ private static Expression GetNumericStringToEnumConversion (
510+ Expression sourceValue ,
511+ Expression fallbackValue ,
512+ Type nonNullableTargetEnumType ,
513+ Type underlyingEnumType )
514+ {
515+ var validEnumValues = Enum
516+ . GetValues ( nonNullableTargetEnumType )
517+ . Cast < object > ( )
518+ . Select ( v => Convert . ChangeType ( v , underlyingEnumType ) . ToString ( ) )
519+ . ToArray ( )
520+ . ToConstantExpression ( typeof ( ICollection < string > ) ) ;
521+
522+ var parsedString = GetStringParseCall ( sourceValue , underlyingEnumType ) ;
523+
524+ var validValueOrFallback = Expression . Condition (
525+ GetIsValidEnumValueCheck ( nonNullableTargetEnumType , sourceValue , validEnumValues ) ,
526+ parsedString . GetConversionTo ( fallbackValue . Type ) ,
527+ fallbackValue ) ;
528+
529+ return validValueOrFallback ;
497530 }
498531 }
499532}
0 commit comments