2
2
using System . Collections . Generic ;
3
3
using System . IO ;
4
4
using System . Linq ;
5
+ using System . Reflection ;
5
6
using ServiceStack . Text . Common ;
6
7
7
8
namespace ServiceStack . Text
@@ -144,6 +145,7 @@ public class CsvWriter<T>
144
145
public static List < string > Headers { get ; set ; }
145
146
146
147
internal static List < GetMemberDelegate < T > > PropertyGetters ;
148
+ internal static List < PropertyInfo > PropertyInfos ;
147
149
148
150
private static readonly WriteObjectDelegate OptimizedWriter ;
149
151
@@ -163,12 +165,15 @@ internal static void Reset()
163
165
Headers = new List < string > ( ) ;
164
166
165
167
PropertyGetters = new List < GetMemberDelegate < T > > ( ) ;
168
+ PropertyInfos = new List < PropertyInfo > ( ) ;
166
169
foreach ( var propertyInfo in TypeConfig < T > . Properties )
167
170
{
168
171
if ( ! propertyInfo . CanRead || propertyInfo . GetGetMethod ( nonPublic : true ) == null ) continue ;
169
172
if ( ! TypeSerializer . CanCreateFromString ( propertyInfo . PropertyType ) ) continue ;
170
173
171
174
PropertyGetters . Add ( propertyInfo . CreateGetter < T > ( ) ) ;
175
+ PropertyInfos . Add ( propertyInfo ) ;
176
+
172
177
var propertyName = propertyInfo . Name ;
173
178
var dcsDataMemberName = propertyInfo . GetDataMemberName ( ) ;
174
179
if ( dcsDataMemberName != null )
@@ -257,6 +262,7 @@ public static void WriteObjectRow(TextWriter writer, object record)
257
262
public static void Write ( TextWriter writer , IEnumerable < T > records )
258
263
{
259
264
if ( writer == null ) return ; //AOT
265
+ if ( records == null ) return ;
260
266
261
267
if ( typeof ( T ) == typeof ( Dictionary < string , string > ) || typeof ( T ) == typeof ( IDictionary < string , string > ) )
262
268
{
@@ -277,10 +283,56 @@ public static void Write(TextWriter writer, IEnumerable<T> records)
277
283
return ;
278
284
}
279
285
280
- if ( ! CsvConfig < T > . OmitHeaders && Headers . Count > 0 )
286
+ var recordsList = records . ToList ( ) ;
287
+
288
+ var headers = Headers ;
289
+ var propGetters = PropertyGetters ;
290
+ var treatAsSingleRow = typeof ( T ) . IsValueType || typeof ( T ) == typeof ( string ) ;
291
+
292
+ if ( ! treatAsSingleRow && JsConfig . ExcludeDefaultValues )
293
+ {
294
+ var hasValues = new bool [ headers . Count ] ;
295
+ var defaultValues = new object [ headers . Count ] ;
296
+ for ( var i = 0 ; i < PropertyInfos . Count ; i ++ )
297
+ {
298
+ defaultValues [ i ] = PropertyInfos [ i ] . PropertyType . GetDefaultValue ( ) ;
299
+ }
300
+
301
+ foreach ( var record in recordsList )
302
+ {
303
+ for ( var i = 0 ; i < propGetters . Count ; i ++ )
304
+ {
305
+ var propGetter = propGetters [ i ] ;
306
+ var value = propGetter ( record ) ;
307
+
308
+ if ( value != null && ! value . Equals ( defaultValues [ i ] ) )
309
+ hasValues [ i ] = true ;
310
+ }
311
+ }
312
+
313
+ if ( hasValues . Any ( x => x == false ) )
314
+ {
315
+ var newHeaders = new List < string > ( ) ;
316
+ var newGetters = new List < GetMemberDelegate < T > > ( ) ;
317
+
318
+ for ( int i = 0 ; i < hasValues . Length ; i ++ )
319
+ {
320
+ if ( hasValues [ i ] )
321
+ {
322
+ newHeaders . Add ( headers [ i ] ) ;
323
+ newGetters . Add ( propGetters [ i ] ) ;
324
+ }
325
+ }
326
+
327
+ headers = newHeaders ;
328
+ propGetters = newGetters ;
329
+ }
330
+ }
331
+
332
+ if ( ! CsvConfig < T > . OmitHeaders && headers . Count > 0 )
281
333
{
282
334
var ranOnce = false ;
283
- foreach ( var header in Headers )
335
+ foreach ( var header in headers )
284
336
{
285
337
CsvWriter . WriteItemSeperatorIfRanOnce ( writer , ref ranOnce ) ;
286
338
@@ -289,25 +341,23 @@ public static void Write(TextWriter writer, IEnumerable<T> records)
289
341
writer . Write ( CsvConfig . RowSeparatorString ) ;
290
342
}
291
343
292
- if ( records == null ) return ;
293
-
294
- if ( typeof ( T ) . IsValueType || typeof ( T ) == typeof ( string ) )
344
+ if ( treatAsSingleRow )
295
345
{
296
- var singleRow = GetSingleRow ( records , typeof ( T ) ) ;
346
+ var singleRow = GetSingleRow ( recordsList , typeof ( T ) ) ;
297
347
WriteRow ( writer , singleRow ) ;
298
348
return ;
299
349
}
300
350
301
- var row = new string [ Headers . Count ] ;
302
- foreach ( var record in records )
351
+ var row = new string [ headers . Count ] ;
352
+ foreach ( var record in recordsList )
303
353
{
304
- for ( var i = 0 ; i < PropertyGetters . Count ; i ++ )
354
+ for ( var i = 0 ; i < propGetters . Count ; i ++ )
305
355
{
306
- var propertyGetter = PropertyGetters [ i ] ;
307
- var value = propertyGetter ( record ) ?? "" ;
356
+ var propGetter = propGetters [ i ] ;
357
+ var value = propGetter ( record ) ?? "" ;
308
358
309
- var strValue = value is string
310
- ? ( string ) value
359
+ var strValue = value is string s
360
+ ? s
311
361
: TypeSerializer . SerializeToString ( value ) . StripQuotes ( ) ;
312
362
313
363
row [ i ] = strValue ;
0 commit comments