1+ /*==============================================================================================================================
2+ | Author Ignia, LLC
3+ | Client Ignia, LLC
4+ | Project Topics Library
5+ \=============================================================================================================================*/
6+ using System . Collections ;
7+ using System . Reflection ;
8+ using OnTopic . Attributes ;
9+
10+ namespace OnTopic . Internal . Reflection {
11+
12+ /*============================================================================================================================
13+ | CLASS: ITEM METADATA
14+ \---------------------------------------------------------------------------------------------------------------------------*/
15+ /// <summary>
16+ /// Provides metadata associated with a given parameter, method, or property.
17+ /// </summary>
18+ internal abstract class ItemMetadata {
19+
20+ /*==========================================================================================================================
21+ | PRIVATE VARIABLES
22+ \-------------------------------------------------------------------------------------------------------------------------*/
23+ private readonly static List < Type > _listTypes = new ( ) ;
24+ private readonly ICustomAttributeProvider _attributeProvider ;
25+ private readonly Type _type = default ! ;
26+
27+ /*==========================================================================================================================
28+ | CONSTRUCTOR
29+ \-------------------------------------------------------------------------------------------------------------------------*/
30+ /// <summary>
31+ /// Initializes a new instance of the <see cref="ItemMetadata"/> class associated with a <see cref="MemberInfo"/> or <see
32+ /// cref="ParameterInfo"/> instance.
33+ /// </summary>
34+ /// <param name="name">The <see cref="Name"/> of the <see cref="MemberInfo"/> or <see cref="ParameterInfo"/>.</param>
35+ /// <param name="attributeProvider">
36+ /// The <see cref="MemberInfo"/> or <see cref="ParameterInfo"/> associated with the <see cref="ItemMetadata"/>.
37+ /// </param>
38+ internal ItemMetadata ( string name , ICustomAttributeProvider attributeProvider ) {
39+
40+ /*------------------------------------------------------------------------------------------------------------------------
41+ | Set Fields
42+ \-----------------------------------------------------------------------------------------------------------------------*/
43+ _attributeProvider = attributeProvider ;
44+
45+ /*------------------------------------------------------------------------------------------------------------------------
46+ | Set Properties
47+ \-----------------------------------------------------------------------------------------------------------------------*/
48+ Name = name ;
49+
50+ }
51+
52+ /*==========================================================================================================================
53+ | NAME
54+ \-------------------------------------------------------------------------------------------------------------------------*/
55+ /// <inheritdoc cref="MemberInfo.Name"/>
56+ internal string Name { get ; }
57+
58+ /*==========================================================================================================================
59+ | TYPE
60+ \-------------------------------------------------------------------------------------------------------------------------*/
61+ /// <summary>
62+ /// Gets the <see cref="Type"/> associated with this member. For properties and get methods, this is the return type. For
63+ /// set methods, this is the type of the parameter.
64+ /// </summary>
65+ /// <remarks>
66+ /// Ideally, the <see cref="Type"/> would be provided as part of the <see cref="ItemMetadata"/> constructor.
67+ /// Unfortunately, however, the logic for setting this type varies based on whether it is a parameter, a methor, or a
68+ /// property. As such, it makes more sense for this logic to be implemented in derived classes. To facilitate this, the
69+ /// <see cref="Type"/> property is provided with an initter, which will automatically set <see cref="IsNullable"/>, <see
70+ /// cref="IsList"/>, and <see cref="IsConvertible"/> when it is set. If this is not done properly, dependency classes will
71+ /// not work properly, and will likely fail. Since there are only two expected derived classes—<see cref="MemberAccessor"
72+ /// /> and <see cref="ParameterMetadata"/>—this shouldn't be a problem. To help avoid this scenario, a <see cref="
73+ /// ArgumentNullException"/> is thrown with instructions in the unexpected case that <see cref="Type"/> is not set.
74+ /// </remarks>
75+ public Type Type {
76+ get {
77+ return _type ?? throw new ArgumentNullException (
78+ nameof ( Type ) ,
79+ $ "This { nameof ( Type ) } property must be initialized by classes derived by { nameof ( ItemMetadata ) } "
80+ ) ;
81+ }
82+ init {
83+ _type = value ;
84+ IsNullable = ! Type . IsValueType || Nullable . GetUnderlyingType ( Type ) != null ;
85+ IsList = isList ( ) ;
86+ IsConvertible = AttributeValueConverter . IsConvertible ( Type ) ;
87+ bool isList ( )
88+ => typeof ( IList ) . IsAssignableFrom ( Type ) || Type . IsGenericType && _listTypes . Contains ( Type . GetGenericTypeDefinition ( ) ) ;
89+ }
90+ }
91+
92+ /*==========================================================================================================================
93+ | IS NULLABLE?
94+ \-------------------------------------------------------------------------------------------------------------------------*/
95+ /// <summary>
96+ /// Determine if the member accepts null values.
97+ /// </summary>
98+ /// <remarks>
99+ /// If the <see cref="Type"/> is a reference type, then it will always accept null values; this doesn't detect C# 9.0
100+ /// nullable reference types.
101+ /// </remarks>
102+ internal bool IsNullable { get ; init ; }
103+
104+ /*==========================================================================================================================
105+ | CUSTOM ATTRIBUTES
106+ \-------------------------------------------------------------------------------------------------------------------------*/
107+ /// <summary>
108+ /// Provides a cached list of custom attributes associated with member.
109+ /// </summary>
110+ internal List < Attribute > CustomAttributes {
111+ get {
112+ _customAttributes ??= _attributeProvider . GetCustomAttributes ( true ) . OfType < Attribute > ( ) . ToList ( ) ;
113+ return _customAttributes ;
114+ }
115+ }
116+
117+ } //Class
118+ } //Namespace
0 commit comments