-
Notifications
You must be signed in to change notification settings - Fork 242
Expand file tree
/
Copy pathReadOnlyGenericDictionaryObjectDescriptorProvider.cs
More file actions
67 lines (59 loc) · 2.83 KB
/
Copy pathReadOnlyGenericDictionaryObjectDescriptorProvider.cs
File metadata and controls
67 lines (59 loc) · 2.83 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
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using HandlebarsDotNet.Collections;
using HandlebarsDotNet.EqualityComparers;
using HandlebarsDotNet.Iterators;
using HandlebarsDotNet.MemberAccessors.DictionaryAccessors;
using HandlebarsDotNet.Polyfills;
using HandlebarsDotNet.Runtime;
namespace HandlebarsDotNet.ObjectDescriptors
{
public sealed class ReadOnlyGenericDictionaryObjectDescriptorProvider : IObjectDescriptorProvider
{
private static readonly MethodInfo CreateDescriptorMethodInfo =
new Func<ObjectDescriptor>(CreateDescriptor<IReadOnlyDictionary<object, object>, object, object>)
.GetMethodInfo().GetGenericMethodDefinition();
private readonly LookupSlim<Type, DeferredValue<Type, Type?>, ReferenceEqualityComparer<Type>> _typeCache = new LookupSlim<Type, DeferredValue<Type, Type?>, ReferenceEqualityComparer<Type>>(new ReferenceEqualityComparer<Type>());
public bool TryGetDescriptor(Type type, [NotNullWhen(true)] out ObjectDescriptor? value)
{
var interfaceType = _typeCache.GetOrAdd(type, InterfaceTypeValueFactory).Value;
if (interfaceType == null)
{
value = ObjectDescriptor.Empty;
return false;
}
var genericArguments = interfaceType.GetGenericArguments();
var descriptorCreator = CreateDescriptorMethodInfo.MakeGenericMethod(type, genericArguments[0], genericArguments[1]);
value = (ObjectDescriptor) descriptorCreator.Invoke(null, ArrayEx.Empty<object>())!;
return true;
}
private static readonly Func<Type, DeferredValue<Type, Type?>> InterfaceTypeValueFactory =
key =>
{
return new DeferredValue<Type, Type?>(key, type =>
{
return type.GetInterfaces()
.Where(i => IntrospectionExtensions.GetTypeInfo(i).IsGenericType)
.Where(i => i.GetGenericTypeDefinition() == typeof(IReadOnlyDictionary<,>))
.FirstOrDefault(i =>
TypeDescriptor.GetConverter(i.GetGenericArguments()[0]).CanConvertFrom(typeof(string))
);
});
};
private static ObjectDescriptor CreateDescriptor<T, TK, TV>()
where T : class, IReadOnlyDictionary<TK, TV>
where TK : notnull
{
return new ObjectDescriptor(
typeof(T),
new ReadOnlyGenericDictionaryAccessor<T, TK, TV>(),
(descriptor, o) => ((T) o).Keys,
self => new ReadOnlyDictionaryIterator<T, TK, TV>()
);
}
}
}