10
10
using System . Runtime . Serialization ;
11
11
using System . Threading ;
12
12
using ServiceStack . Text ;
13
+ using ServiceStack . Text . Json ;
13
14
14
15
namespace ServiceStack
15
16
{
@@ -18,8 +19,16 @@ public class CustomHttpResult { }
18
19
19
20
public static class AutoMappingUtils
20
21
{
21
- public static T ConvertTo < T > ( this object from )
22
+ public static T ConvertTo < T > ( this object from )
22
23
{
24
+ if ( typeof ( IEnumerable ) . IsAssignableFromType ( typeof ( T ) ) )
25
+ {
26
+ var listResult = TranslateListWithElements . TryTranslateCollections (
27
+ from . GetType ( ) , typeof ( T ) , from ) ;
28
+
29
+ return ( T ) listResult ;
30
+ }
31
+
23
32
var to = typeof ( T ) . CreateInstance < T > ( ) ;
24
33
return to . PopulateWith ( from ) ;
25
34
}
@@ -100,7 +109,7 @@ private static object PopulateObjectInternal(object obj, Dictionary<Type, int> r
100
109
}
101
110
return obj ;
102
111
}
103
-
112
+
104
113
private static Dictionary < Type , object > DefaultValueTypes = new Dictionary < Type , object > ( ) ;
105
114
106
115
public static object GetDefaultValue ( this Type type )
@@ -130,7 +139,7 @@ private static readonly ConcurrentDictionary<string, AssignmentDefinition> Assig
130
139
131
140
internal static AssignmentDefinition GetAssignmentDefinition ( Type toType , Type fromType )
132
141
{
133
- var cacheKey = toType . FullName + "<" + fromType . FullName ;
142
+ var cacheKey = CreateCacheKey ( fromType , toType ) ;
134
143
135
144
return AssignmentDefinitionCache . GetOrAdd ( cacheKey , delegate
136
145
{
@@ -157,6 +166,12 @@ internal static AssignmentDefinition GetAssignmentDefinition(Type toType, Type f
157
166
} ) ;
158
167
}
159
168
169
+ internal static string CreateCacheKey ( Type fromType , Type toType )
170
+ {
171
+ var cacheKey = fromType . FullName + ">" + toType . FullName ;
172
+ return cacheKey ;
173
+ }
174
+
160
175
private static Dictionary < string , AssignmentMember > GetMembers ( Type type , bool isReadable )
161
176
{
162
177
var map = new Dictionary < string , AssignmentMember > ( ) ;
@@ -585,82 +600,45 @@ public void Populate(object to, object from,
585
600
Func < PropertyInfo , bool > propertyInfoPredicate ,
586
601
Func < object , Type , bool > valuePredicate )
587
602
{
588
- foreach ( var assignmentEntry in AssignmentMemberMap )
603
+ foreach ( var assignmentEntryMap in AssignmentMemberMap )
589
604
{
590
- var assignmentMember = assignmentEntry . Value ;
591
- var fromMember = assignmentEntry . Value . From ;
592
- var toMember = assignmentEntry . Value . To ;
605
+ var assignmentEntry = assignmentEntryMap . Value ;
606
+ var fromMember = assignmentEntry . From ;
607
+ var toMember = assignmentEntry . To ;
593
608
594
609
if ( fromMember . PropertyInfo != null && propertyInfoPredicate != null )
595
610
{
596
611
if ( ! propertyInfoPredicate ( fromMember . PropertyInfo ) ) continue ;
597
612
}
598
613
614
+ var fromType = fromMember . Type ;
615
+ var toType = toMember . Type ;
599
616
try
600
617
{
601
- var fromValue = assignmentMember . GetValueFn ( from ) ;
618
+ var fromValue = assignmentEntry . GetValueFn ( from ) ;
602
619
603
620
if ( valuePredicate != null )
604
621
{
605
622
if ( ! valuePredicate ( fromValue , fromMember . PropertyInfo . PropertyType ) ) continue ;
606
623
}
607
624
608
- if ( fromMember . Type != toMember . Type )
625
+ if ( fromType != toType )
609
626
{
610
- if ( fromMember . Type == typeof ( string ) )
611
- {
612
- fromValue = TypeSerializer . DeserializeFromString ( ( string ) fromValue , toMember . Type ) ;
613
- }
614
- else if ( toMember . Type == typeof ( string ) )
615
- {
616
- fromValue = TypeSerializer . SerializeToString ( fromValue ) ;
617
- }
618
- else if ( toMember . Type . IsEnum ( ) || fromMember . Type . IsEnum ( ) )
619
- {
620
- if ( toMember . Type . IsEnum ( ) && fromMember . Type . IsEnum ( ) )
621
- {
622
- fromValue = Enum . Parse ( toMember . Type , fromValue . ToString ( ) ) ;
623
- }
624
- else if ( toMember . Type . IsNullableType ( ) )
625
- {
626
- var genericArg = toMember . Type . GenericTypeArguments ( ) [ 0 ] ;
627
- if ( genericArg . IsEnum ( ) )
628
- {
629
- fromValue = Enum . ToObject ( genericArg , fromValue ) ;
630
- }
631
- }
632
- else if ( toMember . Type . IsIntegerType ( ) )
633
- {
634
- fromValue = Enum . ToObject ( fromMember . Type , fromValue ) ;
635
- }
636
- }
637
- else if ( typeof ( IEnumerable ) . IsAssignableFrom ( fromMember . Type ) )
638
- {
639
- var listResult = TranslateListWithElements . TryTranslateToGenericICollection (
640
- fromMember . Type , toMember . Type , fromValue ) ;
641
-
642
- if ( listResult != null )
643
- {
644
- fromValue = listResult ;
645
- }
646
- }
647
- else if ( ! ( toMember . Type . IsValueType ( )
648
- || toMember . Type . IsNullableType ( ) ) )
627
+ var converterFn = TypeConverter . GetTypeConverter ( fromType , toType ) ;
628
+ if ( converterFn != null )
649
629
{
650
- var toValue = toMember . Type . CreateInstance ( ) ;
651
- toValue . PopulateWith ( fromValue ) ;
652
- fromValue = toValue ;
630
+ fromValue = converterFn ( fromValue ) ;
653
631
}
654
632
}
655
633
656
- var setterFn = assignmentMember . SetValueFn ;
634
+ var setterFn = assignmentEntry . SetValueFn ;
657
635
setterFn ( to , fromValue ) ;
658
636
}
659
637
catch ( Exception ex )
660
638
{
661
639
Tracer . Instance . WriteWarning ( "Error trying to set properties {0}.{1} > {2}.{3}:\n {4}" ,
662
- FromType . FullName , fromMember . Type . Name ,
663
- ToType . FullName , toMember . Type . Name , ex ) ;
640
+ FromType . FullName , fromType . Name ,
641
+ ToType . FullName , toType . Name , ex ) ;
664
642
}
665
643
}
666
644
}
@@ -694,4 +672,95 @@ public static PropertyGetterDelegate GetFieldGetterFn(this FieldInfo fieldInfo)
694
672
return PclExport . Instance . GetFieldGetterFn ( fieldInfo ) ;
695
673
}
696
674
}
675
+
676
+ internal static class TypeConverter
677
+ {
678
+ internal static ConcurrentDictionary < string , PropertyGetterDelegate > TypeConvertersCache
679
+ = new ConcurrentDictionary < string , PropertyGetterDelegate > ( ) ;
680
+
681
+ public static PropertyGetterDelegate GetTypeConverter ( Type fromType , Type toType )
682
+ {
683
+ var cacheKey = AutoMappingUtils . CreateCacheKey ( fromType , toType ) ;
684
+
685
+ return TypeConvertersCache . GetOrAdd ( cacheKey ,
686
+ ( Func < string , PropertyGetterDelegate > ) ( key => CreateTypeConverter ( fromType , toType ) ) ) ;
687
+ }
688
+
689
+ public static PropertyGetterDelegate CreateTypeConverter ( Type fromType , Type toType )
690
+ {
691
+ if ( fromType == toType )
692
+ return null ;
693
+
694
+ if ( fromType == typeof ( string ) )
695
+ {
696
+ return fromValue => TypeSerializer . DeserializeFromString ( ( string ) fromValue , toType ) ;
697
+ }
698
+ if ( toType == typeof ( string ) )
699
+ {
700
+ return TypeSerializer . SerializeToString ;
701
+ }
702
+ if ( toType . IsEnum ( ) || fromType . IsEnum ( ) )
703
+ {
704
+ if ( toType . IsEnum ( ) && fromType . IsEnum ( ) )
705
+ {
706
+ return fromValue => Enum . Parse ( toType , fromValue . ToString ( ) ) ;
707
+ }
708
+ if ( toType . IsNullableType ( ) )
709
+ {
710
+ var genericArg = toType . GenericTypeArguments ( ) [ 0 ] ;
711
+ if ( genericArg . IsEnum ( ) )
712
+ {
713
+ return fromValue => Enum . ToObject ( genericArg , fromValue ) ;
714
+ }
715
+ }
716
+ else if ( toType . IsIntegerType ( ) )
717
+ {
718
+ return fromValue => Enum . ToObject ( fromType , fromValue ) ;
719
+ }
720
+ }
721
+ else if ( toType . IsNullableType ( ) )
722
+ {
723
+ return null ;
724
+ }
725
+ else if ( typeof ( IEnumerable ) . IsAssignableFrom ( fromType ) )
726
+ {
727
+ return fromValue =>
728
+ {
729
+ var listResult = TranslateListWithElements . TryTranslateCollections (
730
+ fromType , toType , fromValue ) ;
731
+
732
+ return listResult ?? fromValue ;
733
+ } ;
734
+ }
735
+ else if ( toType . IsValueType ( ) )
736
+ {
737
+ return fromValue => Convert . ChangeType ( fromValue , toType ) ;
738
+ }
739
+ else
740
+ {
741
+ return fromValue =>
742
+ {
743
+ var toValue = toType . CreateInstance ( ) ;
744
+ toValue . PopulateWith ( fromValue ) ;
745
+ return toValue ;
746
+ } ;
747
+ }
748
+
749
+ return null ;
750
+ }
751
+ }
752
+
753
+ internal class TypeConverter < From , To >
754
+ {
755
+ static TypeConverter ( )
756
+ {
757
+ ConvertFn = TypeConverter . CreateTypeConverter ( typeof ( From ) , typeof ( To ) ) ;
758
+ }
759
+
760
+ public static PropertyGetterDelegate ConvertFn ;
761
+ public PropertyGetterDelegate GetConvertFn ( )
762
+ {
763
+ return ConvertFn ;
764
+ }
765
+ }
697
766
}
0 commit comments