zhaolei
2020-11-20 4a2e5b9a21940f11757be37d99f0944e240e908b
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
using PetaPoco.Core;
using PetaPoco.Internal;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
 
namespace PetaPoco
{
    /// <summary>
    ///     This static class manages registation of IMapper instances with PetaPoco
    /// </summary>
    public static class Mappers
    {
        private static ConcurrentDictionary<object, Lazy<IMapper>> _mappers = new ConcurrentDictionary<object, Lazy<IMapper>>();
 
        /// <summary>
        ///     Registers a mapper for all types in a specific assembly
        /// </summary>
        /// <param name="assembly">The assembly whose types are to be managed by this mapper</param>
        /// <param name="mapper">The IMapper implementation</param>
        public static bool Register(Assembly assembly, IMapper mapper) => RegisterInternal(assembly, mapper);
 
        /// <summary>
        ///     Registers a mapper for a single POCO type
        /// </summary>
        /// <param name="type">The type to be managed by this mapper</param>
        /// <param name="mapper">The IMapper implementation</param>
        public static bool Register(Type type, IMapper mapper) => RegisterInternal(type, mapper);
 
        /// <summary>
        ///     Remove all mappers for all types in a specific assembly
        /// </summary>
        /// <param name="assembly">The assembly whose mappers are to be revoked</param>
        public static bool Revoke(Assembly assembly) => RevokeInternal(assembly);
 
        /// <summary>
        ///     Remove the mapper for a specific type
        /// </summary>
        /// <param name="type">The type whose mapper is to be removed</param>
        public static bool Revoke(Type type) => RevokeInternal(type);
 
        /// <summary>
        ///     Revoke an instance of a mapper
        /// </summary>
        /// <param name="mapper">The IMapper to be revkoed</param>
        public static bool Revoke(IMapper mapper)
        {
            var ret = false;
            var m = _mappers.FirstOrDefault(v => v.Value.Value == mapper);
            var key = m.Equals(default(KeyValuePair<object, Lazy<IMapper>>)) ? null : m.Key;
            if (key != null)
            {
                ret = _mappers.TryRemove(key, out var _);
                if (ret) FlushCaches();
            }
            return ret;
        }
 
        /// <summary>
        ///     Revokes all registered mappers.
        /// </summary>
        public static void RevokeAll()
        {
            _mappers.Clear();
            FlushCaches();
        }
 
        /// <summary>
        ///     Retrieve the IMapper implementation to be used for a specified POCO type.
        /// </summary>
        /// <param name="entityType">The entity type to get the mapper for.</param>
        /// <param name="defaultMapper">The default mapper to use when none is registered for the type.</param>
        /// <returns>The mapper for the given type.</returns>
        public static IMapper GetMapper(Type entityType, IMapper defaultMapper)
        {
            if (_mappers.TryGetValue(entityType, out Lazy<IMapper> val))
                return val.Value;
            if (_mappers.TryGetValue(entityType.Assembly, out val))
                return val.Value;
 
            return defaultMapper;
        }
 
        private static bool RegisterInternal(object typeOrAssembly, IMapper mapper)
        {
            var ret = _mappers.TryAdd(typeOrAssembly, new Lazy<IMapper>(() => mapper));
            if (ret) FlushCaches();
            return ret;
        }
 
        private static bool RevokeInternal(object typeOrAssembly)
        {
            var ret = _mappers.TryRemove(typeOrAssembly, out var _);
            if (ret) FlushCaches();
            return ret;
        }
 
        private static void FlushCaches()
        {
            // Whenever a mapper is registered or revoked, we have to assume any generated code is no longer valid.
            // Since this should be a rare occurrence, the simplest approach is to simply dump everything and start over.
            MultiPocoFactory.FlushCaches();
            PocoData.FlushCaches();
        }
    }
}