2
using System.Collections.Generic;
3
using System.Globalization;
5
using System.Reflection;
7
using System.Threading;
8
using ServiceStack.Text.Common;
9
using ServiceStack.Text.Jsv;
10
using ServiceStack.Text.Reflection;
12
namespace ServiceStack.Text
14
public class CsvSerializer
16
private static readonly UTF8Encoding UTF8EncodingWithoutBom = new UTF8Encoding(false);
18
private static Dictionary<Type, WriteObjectDelegate> WriteFnCache = new Dictionary<Type, WriteObjectDelegate>();
20
internal static WriteObjectDelegate GetWriteFn(Type type)
24
WriteObjectDelegate writeFn;
25
if (WriteFnCache.TryGetValue(type, out writeFn)) return writeFn;
27
var genericType = typeof(CsvSerializer<>).MakeGenericType(type);
28
var mi = genericType.GetMethod("WriteFn", BindingFlags.Public | BindingFlags.Static);
29
var writeFactoryFn = (Func<WriteObjectDelegate>)Delegate.CreateDelegate(
30
typeof(Func<WriteObjectDelegate>), mi);
31
writeFn = writeFactoryFn();
33
Dictionary<Type, WriteObjectDelegate> snapshot, newCache;
36
snapshot = WriteFnCache;
37
newCache = new Dictionary<Type, WriteObjectDelegate>(WriteFnCache);
38
newCache[type] = writeFn;
40
} while (!ReferenceEquals(
41
Interlocked.CompareExchange(ref WriteFnCache, newCache, snapshot), snapshot));
47
Tracer.Instance.WriteError(ex);
52
public static string SerializeToCsv<T>(IEnumerable<T> records)
54
var sb = new StringBuilder();
55
using (var writer = new StringWriter(sb, CultureInfo.InvariantCulture))
57
writer.WriteCsv(records);
62
public static string SerializeToString<T>(T value)
64
if (value == null) return null;
65
if (typeof(T) == typeof(string)) return value as string;
67
var sb = new StringBuilder();
68
using (var writer = new StringWriter(sb, CultureInfo.InvariantCulture))
70
CsvSerializer<T>.WriteObject(writer, value);
75
public static void SerializeToWriter<T>(T value, TextWriter writer)
77
if (value == null) return;
78
if (typeof(T) == typeof(string))
83
CsvSerializer<T>.WriteObject(writer, value);
86
public static void SerializeToStream<T>(T value, Stream stream)
88
if (value == null) return;
89
using (var writer = new StreamWriter(stream, UTF8EncodingWithoutBom))
91
CsvSerializer<T>.WriteObject(writer, value);
95
public static void SerializeToStream(object obj, Stream stream)
97
if (obj == null) return;
98
using (var writer = new StreamWriter(stream, UTF8EncodingWithoutBom))
100
var writeFn = GetWriteFn(obj.GetType());
101
writeFn(writer, obj);
105
public static T DeserializeFromStream<T>(Stream stream)
107
throw new NotImplementedException();
110
public static object DeserializeFromStream(Type type, Stream stream)
112
throw new NotImplementedException();
115
public static void WriteLateBoundObject(TextWriter writer, object value)
117
if (value == null) return;
118
var writeFn = GetWriteFn(value.GetType());
119
writeFn(writer, value);
123
internal static class CsvSerializer<T>
125
private static readonly WriteObjectDelegate CacheFn;
127
public static WriteObjectDelegate WriteFn()
132
private const string IgnoreResponseStatus = "ResponseStatus";
134
private static Func<object, object> valueGetter = null;
135
private static WriteObjectDelegate writeElementFn = null;
137
private static WriteObjectDelegate GetWriteFn()
139
PropertyInfo firstCandidate = null;
140
Type bestCandidateEnumerableType = null;
141
PropertyInfo bestCandidate = null;
143
if (typeof(T).IsValueType)
145
return JsvWriter<T>.WriteObject;
148
//If type is an enumerable property itself write that
149
bestCandidateEnumerableType = typeof(T).GetTypeWithGenericTypeDefinitionOf(typeof(IEnumerable<>));
150
if (bestCandidateEnumerableType != null)
152
var elementType = bestCandidateEnumerableType.GetGenericArguments()[0];
153
writeElementFn = CreateWriteFn(elementType);
155
return WriteEnumerableType;
158
//Look for best candidate property if DTO
159
if (typeof(T).IsDto())
161
var properties = TypeConfig<T>.Properties;
162
foreach (var propertyInfo in properties)
164
if (propertyInfo.Name == IgnoreResponseStatus) continue;
166
if (propertyInfo.PropertyType == typeof(string)
167
|| propertyInfo.PropertyType.IsValueType
168
|| propertyInfo.PropertyType == typeof(byte[])) continue;
170
if (firstCandidate == null)
172
firstCandidate = propertyInfo;
175
var enumProperty = propertyInfo.PropertyType
176
.GetTypeWithGenericTypeDefinitionOf(typeof(IEnumerable<>));
178
if (enumProperty != null)
180
bestCandidateEnumerableType = enumProperty;
181
bestCandidate = propertyInfo;
187
//If is not DTO or no candidates exist, write self
188
var noCandidatesExist = bestCandidate == null && firstCandidate == null;
189
if (noCandidatesExist)
194
//If is DTO and has an enumerable property serialize that
195
if (bestCandidateEnumerableType != null)
197
valueGetter = bestCandidate.GetValueGetter(typeof(T));
199
var elementType = bestCandidateEnumerableType.GetGenericArguments()[0];
200
writeElementFn = CreateWriteFn(elementType);
202
return WriteEnumerableProperty;
205
//If is DTO and has non-enumerable, reference type property serialize that
206
valueGetter = firstCandidate.GetValueGetter(typeof(T));
207
writeElementFn = CreateWriteRowFn(firstCandidate.PropertyType);
209
return WriteNonEnumerableType;
212
private static WriteObjectDelegate CreateWriteFn(Type elementType)
214
return CreateCsvWriterFn(elementType, "WriteObject");
217
private static WriteObjectDelegate CreateWriteRowFn(Type elementType)
219
return CreateCsvWriterFn(elementType, "WriteObjectRow");
222
private static WriteObjectDelegate CreateCsvWriterFn(Type elementType, string methodName)
224
var genericType = typeof(CsvWriter<>).MakeGenericType(elementType);
225
var mi = genericType.GetMethod(methodName,
226
BindingFlags.Static | BindingFlags.Public);
228
var writeFn = (WriteObjectDelegate)Delegate.CreateDelegate(typeof(WriteObjectDelegate), mi);
233
public static void WriteEnumerableType(TextWriter writer, object obj)
235
writeElementFn(writer, obj);
238
public static void WriteSelf(TextWriter writer, object obj)
240
CsvWriter<T>.WriteRow(writer, (T)obj);
243
public static void WriteEnumerableProperty(TextWriter writer, object obj)
245
if (obj == null) return; //AOT
247
var enumerableProperty = valueGetter(obj);
248
writeElementFn(writer, enumerableProperty);
251
public static void WriteNonEnumerableType(TextWriter writer, object obj)
253
var nonEnumerableType = valueGetter(obj);
254
writeElementFn(writer, nonEnumerableType);
257
static CsvSerializer()
259
if (typeof(T) == typeof(object))
261
CacheFn = CsvSerializer.WriteLateBoundObject;
265
CacheFn = GetWriteFn();
269
public static void WriteObject(TextWriter writer, object value)
271
CacheFn(writer, value);
b'\\ No newline at end of file'