@@ -28,25 +28,28 @@ internal static class MemberInitExpressionToAggregationExpressionTranslator
2828 {
2929 public static AggregationExpression Translate ( TranslationContext context , MemberInitExpression expression )
3030 {
31- var computedFields = new List < AstComputedField > ( ) ;
32- var classMap = CreateClassMap ( expression . Type ) ;
33-
3431 var newExpression = expression . NewExpression ;
3532 var constructorInfo = newExpression . Constructor ;
36- var constructorParameters = constructorInfo . GetParameters ( ) ;
3733 var constructorArguments = newExpression . Arguments ;
38- var memberNames = new string [ constructorParameters . Length ] ;
39- for ( var i = 0 ; i < constructorParameters . Length ; i ++ )
40- {
41- var constructorParameter = constructorParameters [ i ] ;
42- var memberMap = FindMatchingMemberMap ( expression , classMap , constructorParameter ) ;
4334
44- var argumentExpression = constructorArguments [ i ] ;
45- var argumentTranslation = ExpressionToAggregationExpressionTranslator . Translate ( context , argumentExpression ) ;
46- computedFields . Add ( AstExpression . ComputedField ( memberMap . ElementName , argumentTranslation . Ast ) ) ;
35+ var classMap = CreateClassMap ( expression . Type , constructorInfo , out var creatorMap ) ;
36+ var creatorMapParameters = creatorMap . Arguments ? . ToArray ( ) ;
37+ if ( constructorInfo . GetParameters ( ) . Length > 0 && creatorMapParameters == null )
38+ {
39+ throw new ExpressionNotSupportedException ( expression , because : $ "couldn't find matching properties for constructor parameters.") ;
40+ }
4741
48- memberMap . SetSerializer ( argumentTranslation . Serializer ) ;
49- memberNames [ i ] = memberMap . MemberName ;
42+ var computedFields = new List < AstComputedField > ( ) ;
43+ for ( var i = 0 ; i < creatorMapParameters . Length ; i ++ )
44+ {
45+ var creatorMapParameter = creatorMapParameters [ i ] ;
46+ var constructorArgumentExpression = constructorArguments [ i ] ;
47+ var constructorArgumentTranslation = ExpressionToAggregationExpressionTranslator . Translate ( context , constructorArgumentExpression ) ;
48+ var constructorArgumentType = constructorArgumentExpression . Type ;
49+ var constructorArgumentSerializer = constructorArgumentTranslation . Serializer ?? BsonSerializer . LookupSerializer ( constructorArgumentType ) ;
50+ var memberMap = EnsureMemberMap ( expression , classMap , creatorMapParameter ) ;
51+ memberMap . SetSerializer ( constructorArgumentSerializer ) ;
52+ computedFields . Add ( AstExpression . ComputedField ( memberMap . ElementName , constructorArgumentTranslation . Ast ) ) ;
5053 }
5154
5255 foreach ( var binding in expression . Bindings )
@@ -63,48 +66,69 @@ public static AggregationExpression Translate(TranslationContext context, Member
6366 }
6467
6568 var ast = AstExpression . ComputedDocument ( computedFields ) ;
66-
67- classMap . MapConstructor ( constructorInfo , memberNames ) ;
6869 classMap . Freeze ( ) ;
6970 var serializerType = typeof ( BsonClassMapSerializer < > ) . MakeGenericType ( expression . Type ) ;
7071 var serializer = ( IBsonSerializer ) Activator . CreateInstance ( serializerType , classMap ) ;
7172
7273 return new AggregationExpression ( expression , ast , serializer ) ;
7374 }
7475
75- private static BsonClassMap CreateClassMap ( Type classType )
76+ private static BsonClassMap CreateClassMap ( Type classType , ConstructorInfo constructorInfo , out BsonCreatorMap creatorMap )
7677 {
7778 BsonClassMap baseClassMap = null ;
7879 if ( classType . BaseType != null )
7980 {
80- baseClassMap = CreateClassMap ( classType . BaseType ) ;
81+ baseClassMap = CreateClassMap ( classType . BaseType , null , out _ ) ;
8182 }
8283
8384 var classMapType = typeof ( BsonClassMap < > ) . MakeGenericType ( classType ) ;
84- var constructorInfo = classMapType . GetConstructor ( new Type [ ] { typeof ( BsonClassMap ) } ) ;
85- var classMap = ( BsonClassMap ) constructorInfo . Invoke ( new object [ ] { baseClassMap } ) ;
85+ var classMapConstructorInfo = classMapType . GetConstructor ( new Type [ ] { typeof ( BsonClassMap ) } ) ;
86+ var classMap = ( BsonClassMap ) classMapConstructorInfo . Invoke ( new object [ ] { baseClassMap } ) ;
87+ if ( constructorInfo != null )
88+ {
89+ creatorMap = classMap . MapConstructor ( constructorInfo ) ;
90+ }
91+ else
92+ {
93+ creatorMap = null ;
94+ }
95+
8696 classMap . AutoMap ( ) ;
8797 classMap . IdMemberMap ? . SetElementName ( "_id" ) ; // normally happens when Freeze is called but we need it sooner here
8898
8999 return classMap ;
90100 }
91101
92- private static BsonMemberMap FindMatchingMemberMap ( Expression expression , BsonClassMap classMap , ParameterInfo parameterInfo )
102+ private static BsonMemberMap EnsureMemberMap ( Expression expression , BsonClassMap classMap , MemberInfo creatorMapParameter )
93103 {
94- foreach ( var memberMap in classMap . DeclaredMemberMaps )
104+ var declaringClassMap = classMap ;
105+ while ( declaringClassMap . ClassType != creatorMapParameter . DeclaringType )
95106 {
96- if ( memberMap . MemberType == parameterInfo . ParameterType && memberMap . MemberName . Equals ( parameterInfo . Name , StringComparison . OrdinalIgnoreCase ) )
107+ declaringClassMap = declaringClassMap . BaseClassMap ;
108+
109+ if ( declaringClassMap == null )
97110 {
98- return memberMap ;
111+ throw new ExpressionNotSupportedException ( expression , because : $ "couldn't find matching property for constructor parameter: { creatorMapParameter . Name } " ) ;
99112 }
100113 }
101114
102- if ( classMap . BaseClassMap != null )
115+ foreach ( var memberMap in declaringClassMap . DeclaredMemberMaps )
103116 {
104- return FindMatchingMemberMap ( expression , classMap . BaseClassMap , parameterInfo ) ;
117+ if ( MemberMapMatchesCreatorMapParameter ( memberMap , creatorMapParameter ) )
118+ {
119+ return memberMap ;
120+ }
105121 }
106122
107- throw new ExpressionNotSupportedException ( expression , because : $ "can't find matching property for constructor parameter : { parameterInfo . Name } ") ;
123+ return declaringClassMap . MapMember ( creatorMapParameter ) ;
124+
125+ static bool MemberMapMatchesCreatorMapParameter ( BsonMemberMap memberMap , MemberInfo creatorMapParameter )
126+ {
127+ var memberInfo = memberMap . MemberInfo ;
128+ return
129+ memberInfo . MemberType == creatorMapParameter . MemberType &&
130+ memberInfo . Name . Equals ( creatorMapParameter . Name , StringComparison . OrdinalIgnoreCase ) ;
131+ }
108132 }
109133
110134 private static BsonMemberMap FindMemberMap ( Expression expression , BsonClassMap classMap , string memberName )
0 commit comments