@@ -82,44 +82,19 @@ public static ParserResult<T> Build<T>(
8282 var specPropsWithValue =
8383 optionSpecPropsResult . SucceededWith ( ) . Concat ( valueSpecPropsResult . SucceededWith ( ) ) . Memorize ( ) ;
8484
85- var setPropertyErrors = new List < Error > ( ) ;
85+ var setPropertyErrors = new List < Error > ( ) ;
8686
87- Func < T > buildMutable = ( ) =>
87+ //build the instance, determining if the type is mutable or not.
88+ T instance ;
89+ if ( typeInfo . IsMutable ( ) == true )
8890 {
89- var mutable = factory . MapValueOrDefault ( f => f ( ) , Activator . CreateInstance < T > ( ) ) ;
90- setPropertyErrors . AddRange ( mutable . SetProperties ( specPropsWithValue , sp => sp . Value . IsJust ( ) , sp => sp . Value . FromJustOrFail ( ) ) ) ;
91- setPropertyErrors . AddRange ( mutable . SetProperties (
92- specPropsWithValue ,
93- sp => sp . Value . IsNothing ( ) && sp . Specification . DefaultValue . IsJust ( ) ,
94- sp => sp . Specification . DefaultValue . FromJustOrFail ( ) ) ) ;
95- setPropertyErrors . AddRange ( mutable . SetProperties (
96- specPropsWithValue ,
97- sp =>
98- sp . Value . IsNothing ( ) && sp . Specification . TargetType == TargetType . Sequence
99- && sp . Specification . DefaultValue . MatchNothing ( ) ,
100- sp => sp . Property . PropertyType . GetTypeInfo ( ) . GetGenericArguments ( ) . Single ( ) . CreateEmptyArray ( ) ) ) ;
101- return mutable ;
102- } ;
103-
104- Func < T > buildImmutable = ( ) =>
91+ instance = BuildMutable ( factory , specPropsWithValue , setPropertyErrors ) ;
92+ }
93+ else
10594 {
106- var ctor = typeInfo . GetTypeInfo ( ) . GetConstructor ( ( from sp in specProps select sp . Property . PropertyType ) . ToArray ( ) ) ;
107- var values = ( from prms in ctor . GetParameters ( )
108- join sp in specPropsWithValue on prms . Name . ToLower ( ) equals sp . Property . Name . ToLower ( ) into spv
109- from sp in spv . DefaultIfEmpty ( )
110- select
111- sp == null
112- ? specProps . First ( s => String . Equals ( s . Property . Name , prms . Name , StringComparison . CurrentCultureIgnoreCase ) )
113- . Property . PropertyType . GetDefaultValue ( )
114- : sp . Value . GetValueOrDefault (
115- sp . Specification . DefaultValue . GetValueOrDefault (
116- sp . Specification . ConversionType . CreateDefaultForImmutable ( ) ) ) ) . ToArray ( ) ;
117- var immutable = ( T ) ctor . Invoke ( values ) ;
118- return immutable ;
119- } ;
120-
121- var instance = typeInfo . IsMutable ( ) ? buildMutable ( ) : buildImmutable ( ) ;
122-
95+ instance = BuildImmutable ( typeInfo , factory , specProps , specPropsWithValue , setPropertyErrors ) ;
96+ }
97+
12398 var validationErrors = specPropsWithValue . Validate ( SpecificationPropertyRules . Lookup ( tokens ) ) ;
12499
125100 var allErrors =
@@ -150,5 +125,67 @@ from sp in spv.DefaultIfEmpty()
150125
151126 return result ;
152127 }
128+
129+ private static T BuildMutable < T > ( Maybe < Func < T > > factory , IEnumerable < SpecificationProperty > specPropsWithValue , List < Error > setPropertyErrors )
130+ {
131+ var mutable = factory . MapValueOrDefault ( f => f ( ) , Activator . CreateInstance < T > ( ) ) ;
132+
133+ setPropertyErrors . AddRange (
134+ mutable . SetProperties (
135+ specPropsWithValue ,
136+ sp => sp . Value . IsJust ( ) ,
137+ sp => sp . Value . FromJustOrFail ( )
138+ )
139+ ) ;
140+
141+ setPropertyErrors . AddRange (
142+ mutable . SetProperties (
143+ specPropsWithValue ,
144+ sp => sp . Value . IsNothing ( ) && sp . Specification . DefaultValue . IsJust ( ) ,
145+ sp => sp . Specification . DefaultValue . FromJustOrFail ( )
146+ )
147+ ) ;
148+
149+ setPropertyErrors . AddRange (
150+ mutable . SetProperties (
151+ specPropsWithValue ,
152+ sp => sp . Value . IsNothing ( )
153+ && sp . Specification . TargetType == TargetType . Sequence
154+ && sp . Specification . DefaultValue . MatchNothing ( ) ,
155+ sp => sp . Property . PropertyType . GetTypeInfo ( ) . GetGenericArguments ( ) . Single ( ) . CreateEmptyArray ( )
156+ )
157+ ) ;
158+
159+ return mutable ;
160+ }
161+
162+ private static T BuildImmutable < T > ( Type typeInfo , Maybe < Func < T > > factory , IEnumerable < SpecificationProperty > specProps , IEnumerable < SpecificationProperty > specPropsWithValue , List < Error > setPropertyErrors )
163+ {
164+ var ctor = typeInfo . GetTypeInfo ( ) . GetConstructor (
165+ specProps . Select ( sp => sp . Property . PropertyType ) . ToArray ( )
166+ ) ;
167+
168+ if ( ctor == null )
169+ {
170+ throw new InvalidOperationException ( $ "Type appears to be immutable, but no constructor found for type { typeInfo . FullName } to accept values.") ;
171+ }
172+
173+ var values =
174+ ( from prms in ctor . GetParameters ( )
175+ join sp in specPropsWithValue on prms . Name . ToLower ( ) equals sp . Property . Name . ToLower ( ) into spv
176+ from sp in spv . DefaultIfEmpty ( )
177+ select
178+ sp == null
179+ ? specProps . First ( s => String . Equals ( s . Property . Name , prms . Name , StringComparison . CurrentCultureIgnoreCase ) )
180+ . Property . PropertyType . GetDefaultValue ( )
181+ : sp . Value . GetValueOrDefault (
182+ sp . Specification . DefaultValue . GetValueOrDefault (
183+ sp . Specification . ConversionType . CreateDefaultForImmutable ( ) ) ) ) . ToArray ( ) ;
184+
185+ var immutable = ( T ) ctor . Invoke ( values ) ;
186+
187+ return immutable ;
188+ }
189+
153190 }
154- }
191+ }
0 commit comments