forked from sebastienros/fluid
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDefaultMemberAccessStrategy.cs
106 lines (88 loc) · 3.46 KB
/
DefaultMemberAccessStrategy.cs
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
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace Fluid
{
public class DefaultMemberAccessStrategy : MemberAccessStrategy
{
private readonly object _synLock = new();
private Dictionary<Type, Dictionary<string, IMemberAccessor>> _map = new Dictionary<Type, Dictionary<string, IMemberAccessor>>();
public override IMemberAccessor GetAccessor(Type type, string name)
{
// Look for specific property map
if (TryGetAccessor(type, name, out var accessor))
{
return accessor;
}
return GetAccessorUnlikely(type, name);
}
private IMemberAccessor GetAccessorUnlikely(Type type, string name)
{
var currentType = type.GetTypeInfo().BaseType;
while (currentType != typeof(object) && currentType != null)
{
// Look for specific property map
if (TryGetAccessor(currentType, name, out var accessor))
{
return accessor;
}
currentType = currentType.GetTypeInfo().BaseType;
}
// Search for accessors defined on interfaces
foreach (var interfaceType in type.GetTypeInfo().GetInterfaces())
{
// NB: Here we could also register this accessor in typeMap[type] such that
// next lookup on this type won't need to resolve its interfaces
if (TryGetAccessor(interfaceType, name, out var accessor))
{
return accessor;
}
}
return null;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool TryGetAccessor(Type type, string name, out IMemberAccessor accessor)
{
if (_map.TryGetValue(type, out var typeMap))
{
if (typeMap.TryGetValue(name, out accessor) || typeMap.TryGetValue("*", out accessor))
{
return true;
}
}
accessor = null;
return false;
}
public override void Register(Type type, IEnumerable<KeyValuePair<string, IMemberAccessor>> accessors)
{
if (accessors is null)
{
throw new ArgumentNullException(nameof(accessors));
}
// Create a copy of the current dictionary since types are added during the initialization of the app.
lock (_synLock)
{
// Clone current dictionary
var temp = new Dictionary<Type, Dictionary<string, IMemberAccessor>>(_map);
// Clone inner dictionaries
foreach (var typeEntry in temp)
{
var entry = new Dictionary<string, IMemberAccessor>(typeEntry.Value);
}
if (!temp.TryGetValue(type, out var typeMap))
{
typeMap = new Dictionary<string, IMemberAccessor>(IgnoreCasing
? StringComparer.OrdinalIgnoreCase
: StringComparer.Ordinal);
temp[type] = typeMap;
}
foreach (var accessor in accessors)
{
typeMap[accessor.Key] = accessor.Value;
}
_map = temp;
}
}
}
}