1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
// Copyright 2009-2022 Josh Close
// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0.
// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0.
// https://github.com/JoshClose/CsvHelper
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using CsvHelper.Configuration;
using CsvHelper.Configuration.Attributes;
namespace CsvHelper.TypeConversion
{
/// <summary>
/// Converts an <see cref="Enum"/> to and from a <see cref="string"/>.
/// </summary>
public class EnumConverter : DefaultTypeConverter
{
private readonly Type type;
private readonly Dictionary<string, string> enumNamesByAttributeNames = new Dictionary<string, string>();
private readonly Dictionary<string, string> enumNamesByAttributeNamesIgnoreCase = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary<object, string> attributeNamesByEnumValues = new Dictionary<object, string>();
// enumNamesByAttributeNames
// enumNamesByAttributeNamesIgnoreCase
// [Name("Foo")]:One
// attributeNamesByEnumValues
// 1:[Name("Foo")]
/// <summary>
/// Creates a new <see cref="EnumConverter"/> for the given <see cref="Enum"/> <see cref="System.Type"/>.
/// </summary>
/// <param name="type">The type of the Enum.</param>
public EnumConverter(Type type)
{
if (!typeof(Enum).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()))
{
throw new ArgumentException($"'{type.FullName}' is not an Enum.");
}
this.type = type;
foreach (var value in Enum.GetValues(type))
{
var enumName = Enum.GetName(type, value) ?? string.Empty;
var nameAttribute = type.GetField(enumName)?.GetCustomAttribute<NameAttribute>();
if (nameAttribute != null && nameAttribute.Names.Length > 0)
{
foreach (var attributeName in nameAttribute.Names)
{
if (!enumNamesByAttributeNames.ContainsKey(attributeName))
{
enumNamesByAttributeNames.Add(attributeName, enumName);
}
if (!enumNamesByAttributeNamesIgnoreCase.ContainsKey(attributeName))
{
enumNamesByAttributeNamesIgnoreCase.Add(attributeName, enumName);
}
if (!attributeNamesByEnumValues.ContainsKey(value))
{
attributeNamesByEnumValues.Add(value, attributeName);
}
}
}
}
}
/// <inheritdoc/>
public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData)
{
var ignoreCase = memberMapData.TypeConverterOptions.EnumIgnoreCase ?? false;
if (text != null)
{
var dict = ignoreCase
? enumNamesByAttributeNamesIgnoreCase
: enumNamesByAttributeNames;
if (dict.TryGetValue(text, out var name))
{
return Enum.Parse(type, name);
}
}
#if NET45 || NET47 || NETSTANDARD2_0
try
{
return Enum.Parse(type, text, ignoreCase);
}
catch
{
return base.ConvertFromString(text, row, memberMapData);
}
#else
if (Enum.TryParse(type, text, ignoreCase, out var value))
{
return value;
}
else
{
return base.ConvertFromString(text, row, memberMapData);
}
#endif
}
/// <inheritdoc/>
public override string? ConvertToString(object? value, IWriterRow row, MemberMapData memberMapData)
{
if (value != null && attributeNamesByEnumValues.TryGetValue(value, out var name))
{
return name;
}
return base.ConvertToString(value, row, memberMapData);
}
}
}
|