• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

loresoft / FluentCommand / 23278216331

19 Mar 2026 03:19AM UTC coverage: 57.398% (+0.7%) from 56.658%
23278216331

push

github

pwelter34
Enable nullable and improve source generators

1403 of 3069 branches covered (45.72%)

Branch coverage included in aggregate %.

527 of 907 new or added lines in 58 files covered. (58.1%)

22 existing lines in 10 files now uncovered.

4288 of 6846 relevant lines covered (62.64%)

330.58 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

41.43
/src/FluentCommand/Reflection/MemberAccessor.cs
1
using System.ComponentModel.DataAnnotations;
2
using System.ComponentModel.DataAnnotations.Schema;
3
using System.Diagnostics;
4
using System.Reflection;
5

6
namespace FluentCommand.Reflection;
7

8
/// <summary>
9
/// Provides a base implementation for member accessors, enabling reflection-based access and metadata retrieval
10
/// for entity members (properties or fields), including support for data annotation attributes and database mapping.
11
/// </summary>
12
[DebuggerDisplay("Name: {Name}")]
13
public abstract class MemberAccessor : IMemberAccessor, IEquatable<IMemberAccessor>
14
{
15
    private readonly Lazy<ColumnAttribute?> _columnAttribute;
16
    private readonly Lazy<KeyAttribute?> _keyAttribute;
17
    private readonly Lazy<NotMappedAttribute?> _notMappedAttribute;
18
    private readonly Lazy<DatabaseGeneratedAttribute?> _databaseGeneratedAttribute;
19
    private readonly Lazy<ConcurrencyCheckAttribute?> _concurrencyCheckAttribute;
20
    private readonly Lazy<ForeignKeyAttribute?> _foreignKeyAttribute;
21
    private readonly Lazy<RequiredAttribute?> _requiredAttribute;
22
    private readonly Lazy<DisplayAttribute?> _displayAttribute;
23
    private readonly Lazy<DisplayFormatAttribute?> _displayFormatAttribute;
24

25

26
    /// <summary>
27
    /// Initializes a new instance of the <see cref="MemberAccessor"/> class using the specified <see cref="MemberInfo"/>.
28
    /// </summary>
29
    /// <param name="memberInfo">The reflection metadata for the member to be accessed.</param>
30
    /// <exception cref="ArgumentNullException">Thrown if <paramref name="memberInfo"/> is <c>null</c>.</exception>
31
    protected MemberAccessor(MemberInfo memberInfo)
12✔
32
    {
33
        MemberInfo = memberInfo ?? throw new ArgumentNullException(nameof(memberInfo));
12!
34

35
        _columnAttribute = new Lazy<ColumnAttribute?>(() => MemberInfo.GetCustomAttribute<ColumnAttribute>(true));
23✔
36
        _keyAttribute = new Lazy<KeyAttribute?>(() => MemberInfo.GetCustomAttribute<KeyAttribute>(true));
16✔
37
        _notMappedAttribute = new Lazy<NotMappedAttribute?>(() => MemberInfo.GetCustomAttribute<NotMappedAttribute>(true));
17✔
38
        _databaseGeneratedAttribute = new Lazy<DatabaseGeneratedAttribute?>(() => MemberInfo.GetCustomAttribute<DatabaseGeneratedAttribute>(true));
16✔
39
        _concurrencyCheckAttribute = new Lazy<ConcurrencyCheckAttribute?>(() => MemberInfo.GetCustomAttribute<ConcurrencyCheckAttribute>(true));
12✔
40
        _foreignKeyAttribute = new Lazy<ForeignKeyAttribute?>(() => MemberInfo.GetCustomAttribute<ForeignKeyAttribute>(true));
12✔
41
        _requiredAttribute = new Lazy<RequiredAttribute?>(() => MemberInfo.GetCustomAttribute<RequiredAttribute>(true));
16✔
42
        _displayAttribute = new Lazy<DisplayAttribute?>(() => MemberInfo.GetCustomAttribute<DisplayAttribute>(true));
16✔
43
        _displayFormatAttribute = new Lazy<DisplayFormatAttribute?>(() => MemberInfo.GetCustomAttribute<DisplayFormatAttribute>(true));
12✔
44
    }
12✔
45

46
    /// <summary>
47
    /// Gets the <see cref="Type"/> of the member (property or field).
48
    /// </summary>
49
    /// <value>The <see cref="Type"/> representing the member's data type.</value>
50
    public abstract Type MemberType { get; }
51

52
    /// <summary>
53
    /// Gets the <see cref="MemberInfo"/> instance for the accessor, providing reflection metadata.
54
    /// </summary>
55
    /// <value>The <see cref="MemberInfo"/> for the member.</value>
56
    public MemberInfo MemberInfo { get; }
32✔
57

58
    /// <summary>
59
    /// Gets the name of the member as defined in the entity.
60
    /// </summary>
61
    /// <value>The member's name.</value>
62
    public abstract string Name { get; }
63

64
    /// <summary>
65
    /// Gets a value indicating whether this member has a getter method.
66
    /// </summary>
67
    /// <value><c>true</c> if the member has a getter; otherwise, <c>false</c>.</value>
68
    public abstract bool HasGetter { get; }
69

70
    /// <summary>
71
    /// Gets a value indicating whether this member has a setter method.
72
    /// </summary>
73
    /// <value><c>true</c> if the member has a setter; otherwise, <c>false</c>.</value>
74
    public abstract bool HasSetter { get; }
75

76
    /// <summary>
77
    /// Gets the name of the database column that the member is mapped to.
78
    /// This value is determined by the <see cref="ColumnAttribute.Name"/> property if specified,
79
    /// otherwise it defaults to the member name.
80
    /// </summary>
81
    /// <value>The mapped database column name.</value>
82
    public string Column => _columnAttribute.Value?.Name ?? Name;
65✔
83

84
    /// <summary>
85
    /// Gets the database provider-specific data type of the column the member is mapped to.
86
    /// This value is determined by the <see cref="ColumnAttribute.TypeName"/> property if specified.
87
    /// </summary>
88
    /// <value>The provider-specific column data type.</value>
NEW
89
    public string? ColumnType => _columnAttribute.Value?.TypeName;
×
90

91
    /// <summary>
92
    /// Gets the zero-based order of the column the member is mapped to in the database.
93
    /// This value is determined by the <see cref="ColumnAttribute.Order"/> property if specified.
94
    /// </summary>
95
    /// <value>The zero-based column order, or <c>null</c> if not specified.</value>
96
    public int? ColumnOrder => _columnAttribute.Value?.Order;
×
97

98
    /// <summary>
99
    /// Gets a value indicating whether this member is the primary key for the entity.
100
    /// This is determined by the presence of the <see cref="KeyAttribute"/>.
101
    /// </summary>
102
    /// <value><c>true</c> if this member is a primary key; otherwise, <c>false</c>.</value>
103
    public bool IsKey => _keyAttribute.Value != null;
5✔
104

105
    /// <summary>
106
    /// Gets a value indicating whether this member should be excluded from database mapping.
107
    /// This is determined by the presence of the <see cref="NotMappedAttribute"/>.
108
    /// </summary>
109
    /// <value><c>true</c> if this member is not mapped to a database column; otherwise, <c>false</c>.</value>
110
    public bool IsNotMapped => _notMappedAttribute.Value != null;
5✔
111

112
    /// <summary>
113
    /// Gets a value indicating whether this member participates in optimistic concurrency checks.
114
    /// This is determined by the presence of the <see cref="ConcurrencyCheckAttribute"/>.
115
    /// </summary>
116
    /// <value><c>true</c> if this member is used for concurrency checking; otherwise, <c>false</c>.</value>
UNCOV
117
    public bool IsConcurrencyCheck => _concurrencyCheckAttribute.Value != null;
×
118

119
    /// <summary>
120
    /// Gets a value indicating whether this member's value is generated by the database.
121
    /// This is determined by the presence of the <see cref="DatabaseGeneratedAttribute"/> and its option.
122
    /// </summary>
123
    /// <value><c>true</c> if the value is generated by the database; otherwise, <c>false</c>.</value>
124
    public bool IsDatabaseGenerated => _databaseGeneratedAttribute.Value != null
14!
125
        && _databaseGeneratedAttribute.Value.DatabaseGeneratedOption != DatabaseGeneratedOption.None;
14✔
126

127
    /// <summary>
128
    /// Gets the name of the associated navigation property or foreign key(s) for this member.
129
    /// This value is determined by the <see cref="ForeignKeyAttribute.Name"/> property if specified.
130
    /// </summary>
131
    /// <value>The name of the navigation property or foreign key(s), or <c>null</c> if not applicable.</value>
NEW
132
    public string? ForeignKey => _foreignKeyAttribute.Value?.Name;
×
133

134
    /// <summary>
135
    /// Gets a value indicating whether this member is required (non-nullable or marked as required).
136
    /// This is determined by the presence of the <see cref="RequiredAttribute"/>.
137
    /// </summary>
138
    /// <value><c>true</c> if the member is required; otherwise, <c>false</c>.</value>
139
    public bool IsRequired => _requiredAttribute.Value != null;
5✔
140

141
    /// <summary>
142
    /// Gets the display name of the member, typically used for UI or reporting purposes.
143
    /// This value is determined by the <see cref="DisplayAttribute.Name"/> property if specified; otherwise, the member name.
144
    /// </summary>
145
    /// <value>The display name of the member.</value>
146
    public string DisplayName => _displayAttribute.Value?.Name ?? Name;
5!
147

148
    /// <summary>
149
    /// Gets the format string used to display the member's value, if specified.
150
    /// This value is determined by the <see cref="DisplayFormatAttribute.DataFormatString"/> property if present.
151
    /// </summary>
152
    /// <value>
153
    /// The data format string for display formatting, or <c>null</c> if not specified.
154
    /// </value>
NEW
155
    public string? DataFormatString => _displayFormatAttribute.Value?.DataFormatString;
×
156

157
    /// <summary>
158
    /// Returns the value of the member for the specified object instance.
159
    /// </summary>
160
    /// <param name="instance">The object whose member value will be returned.</param>
161
    /// <returns>The value of the member for the given <paramref name="instance"/>.</returns>
162
    public abstract object? GetValue(object instance);
163

164
    /// <summary>
165
    /// Sets the value of the member for the specified object instance.
166
    /// </summary>
167
    /// <param name="instance">The object whose member value will be set.</param>
168
    /// <param name="value">The new value to assign to the member.</param>
169
    public abstract void SetValue(object instance, object? value);
170

171

172
    /// <summary>
173
    /// Determines whether the specified <see cref="IMemberAccessor"/> is equal to this instance.
174
    /// </summary>
175
    /// <param name="other">The <see cref="IMemberAccessor"/> to compare with this instance.</param>
176
    /// <returns><c>true</c> if the specified accessor is equal to this instance; otherwise, <c>false</c>.</returns>
177
    public bool Equals(IMemberAccessor? other)
178
    {
NEW
179
        if (other is null)
×
180
            return false;
×
181

182
        if (ReferenceEquals(this, other))
×
183
            return true;
×
184

NEW
185
        if (other is MemberAccessor otherAccessor)
×
NEW
186
            return Equals(otherAccessor.MemberInfo, MemberInfo);
×
187

NEW
188
        return string.Equals(other.Name, Name, StringComparison.Ordinal);
×
189
    }
190

191
    /// <summary>
192
    /// Determines whether the specified <see cref="object"/> is equal to this instance.
193
    /// </summary>
194
    /// <param name="obj">The <see cref="object"/> to compare with this instance.</param>
195
    /// <returns><c>true</c> if the specified object is equal to this instance; otherwise, <c>false</c>.</returns>
196
    public override bool Equals(object? obj)
197
    {
NEW
198
        if (obj is null)
×
199
            return false;
×
200

201
        if (ReferenceEquals(this, obj))
×
202
            return true;
×
203

NEW
204
        return obj is IMemberAccessor other && Equals(other);
×
205
    }
206

207
    /// <summary>
208
    /// Returns a hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
209
    /// </summary>
210
    /// <returns>A hash code for this instance.</returns>
211
    public override int GetHashCode()
212
    {
213
        return MemberInfo.GetHashCode();
×
214
    }
215
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc