Repository navigation
Expand file tree
/
Copy pathDictionaryComparerExample.cs
More file actions
126 lines (110 loc) · 6.1 KB
/
Copy pathDictionaryComparerExample.cs
File metadata and controls
126 lines (110 loc) · 6.1 KB
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
122
123
124
125
126
using System;
using System.Collections.Generic;
using Mammoth.LiteMapper;
namespace Mammoth.LiteMapper.Samples.Collections
{
public static class DictionaryComparerExample
{
public static void Run()
{
var numbers = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase) { ["A"] = 7 };
CheckWidened(DictionaryComparerMapper.WidenToDictionary(numbers), numbers);
CheckWidened(DictionaryComparerMapper.WidenToInterface(numbers), numbers);
CheckWidened(DictionaryComparerMapper.WidenToReadOnlyDictionary(numbers), numbers);
var values = new Dictionary<string, DictionaryValueSource>(StringComparer.OrdinalIgnoreCase)
{
["A"] = new DictionaryValueSource { Value = 7 },
};
CheckStructural(DictionaryComparerMapper.MapToDictionary(values), values);
CheckStructural(DictionaryComparerMapper.MapToInterface(values), values);
CheckStructural(DictionaryComparerMapper.MapToReadOnlyDictionary(values), values);
CheckConvertedKeys(ConvertedDictionaryKeyMapper.ToDictionary);
CheckConvertedKeys(ConvertedDictionaryKeyMapper.ToInterface);
CheckConvertedKeys(ConvertedDictionaryKeyMapper.ToReadOnlyDictionary);
}
private static void CheckWidened(object mapped, Dictionary<string, int> source)
{
if (!(mapped is Dictionary<string, long> dictionary) || dictionary.Count != 1 ||
!dictionary.TryGetValue("a", out var value) || value != 7 ||
ReferenceEquals(source, mapped) || !ReferenceEquals(dictionary.Comparer, source.Comparer))
{
throw new InvalidOperationException("Widening dictionary values must preserve the key comparer without aliasing.");
}
dictionary["A"] = 9;
dictionary.Add("B", 2);
if (source.Count != 1 || source["A"] != 7 || dictionary.Count != 2)
{
throw new InvalidOperationException("Changing a widened dictionary must not change its source.");
}
}
private static void CheckStructural(object mapped, Dictionary<string, DictionaryValueSource> source)
{
if (!(mapped is Dictionary<string, DictionaryValueTarget> dictionary) || dictionary.Count != 1 ||
!dictionary.TryGetValue("a", out var value) || value.Value != 7 ||
ReferenceEquals(source, mapped) || ReferenceEquals(source["A"], value) ||
!ReferenceEquals(dictionary.Comparer, source.Comparer))
{
throw new InvalidOperationException("Structural dictionary values must preserve the key comparer without aliasing.");
}
value.Value = 9;
dictionary.Add("B", new DictionaryValueTarget { Value = 2 });
if (source.Count != 1 || source["A"].Value != 7 || dictionary.Count != 2)
{
throw new InvalidOperationException("Changing a mapped dictionary or value must not change its source.");
}
}
private static void CheckConvertedKeys(Func<Dictionary<string, int>, object> map)
{
var source = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase) { ["A"] = 7 };
var mapped = map(source);
if (!(mapped is Dictionary<string, int> dictionary) || dictionary.Count != 1 ||
!dictionary.TryGetValue("a", out var value) || value != 7 || dictionary.ContainsKey("A") ||
ReferenceEquals(source, mapped) || !ReferenceEquals(dictionary.Comparer, EqualityComparer<string>.Default))
{
throw new InvalidOperationException("Same-type converted keys must use the destination default comparer.");
}
dictionary.Add("A", 9);
if (source.Count != 1 || source["A"] != 7 || dictionary.Count != 2)
{
throw new InvalidOperationException("Converted keys must allow distinct default-comparer keys without changing the source.");
}
var colliding = new Dictionary<string, int>(StringComparer.Ordinal) { ["A"] = 1, ["a"] = 2 };
try
{
map(colliding);
}
catch (ArgumentException)
{
return;
}
throw new InvalidOperationException("Converted dictionary key collisions must throw using Add semantics.");
}
}
[LiteMapper]
public static partial class DictionaryComparerMapper
{
public static partial Dictionary<string, long> WidenToDictionary(Dictionary<string, int> source);
public static partial IDictionary<string, long> WidenToInterface(Dictionary<string, int> source);
public static partial IReadOnlyDictionary<string, long> WidenToReadOnlyDictionary(Dictionary<string, int> source);
public static partial Dictionary<string, DictionaryValueTarget> MapToDictionary(Dictionary<string, DictionaryValueSource> source);
public static partial IDictionary<string, DictionaryValueTarget> MapToInterface(Dictionary<string, DictionaryValueSource> source);
public static partial IReadOnlyDictionary<string, DictionaryValueTarget> MapToReadOnlyDictionary(Dictionary<string, DictionaryValueSource> source);
}
[LiteMapper]
public static partial class ConvertedDictionaryKeyMapper
{
public static partial Dictionary<string, int> ToDictionary(Dictionary<string, int> source);
public static partial IDictionary<string, int> ToInterface(Dictionary<string, int> source);
public static partial IReadOnlyDictionary<string, int> ToReadOnlyDictionary(Dictionary<string, int> source);
[MappingConverter]
private static string NormalizeKey(string key) => key.ToLowerInvariant();
}
public sealed class DictionaryValueSource
{
public int Value { get; set; }
}
public sealed class DictionaryValueTarget
{
public long Value { get; set; }
}
}