-
Notifications
You must be signed in to change notification settings - Fork 2
/
StringValueObject.cs
134 lines (105 loc) · 3.96 KB
/
StringValueObject.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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#region Usings
using Records.Shared.Domain.Exceptions;
using Records.Shared.Domain.Models;
using Throw;
#endregion
namespace Records.Shared.Domain.ValueObjects;
/// <summary>
/// A value object base class for strings value objects (non nullable).
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage(
"StyleCop.CSharp.OrderingRules",
"SA1201:Elements should appear in the correct order",
Justification = "Prefere to have the Build() inside the constructor region.")]
public abstract class StringValueObject : ValueObject
{
#region Declarations
/// <summary>Regex always valid (default).</summary>
private const string RegexValid = ".*";
private readonly int _maxLength;
private readonly int _minLength;
private readonly string _valueName;
private readonly string _regex;
#endregion
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="StringValueObject"/> value object.
/// </summary>
/// <param name="value">The string value.</param>
/// <param name="valueName">The name to show in the exception if its value is invalid.</param>
/// <param name="maxLength">The maximum length to validate (send 0 to skip the validation).</param>
/// <param name="minLength">The minimum length to validate (default 0).</param>
/// <param name="regex">Regular expression to check (default ".*", anything).</param>
protected StringValueObject(
string? value,
string valueName,
int maxLength,
int minLength = 0,
string regex = RegexValid)
{
_valueName = valueName;
_maxLength = maxLength;
_minLength = minLength;
_regex = regex;
EnsureIsValid(value);
Value = value!; // Null validated.
}
// NOTE: Static methods can not be abstracts in C#, so this method must replicate in each derived class.
////public static StringValueObject Build(string? value)
////{
//// StringValueObject valueObject = new StringValueObject(value);
//// return valueObject;
////}
#endregion
#region Properties
/// <summary>The value.</summary>
public string Value { get; }
/// <summary>Gets a value indicating whether the ValueObject has a value other than null or empty.</summary>
/// <remarks>Empty string is taken as no value.</remarks>
public bool HasValue => !string.IsNullOrEmpty(Value);
/// <summary>Gets a value indicating whether the ValueObject has not a value.</summary>
public bool IsEmpty => string.IsNullOrEmpty(Value);
#endregion
#region Methods
/// <summary>
/// Implicit operator that returns its value.
/// </summary>
/// <param name="valueObject">The value object.</param>
public static implicit operator string(StringValueObject valueObject)
{
return valueObject.Value!;
}
/// <inheritdoc />
public override string ToString()
{
return Value!;
}
/// <summary>
/// Asserts that the arguments to create the <see cref="StringValueObject"/> value object are valid.
/// </summary>
/// <param name="value">The value.</param>
/// <exception cref="DomainValidationException">If some argument is invalid.</exception>
protected void EnsureIsValid(string? value)
{
// INFO: To build regex, ask ChatGpt ;).
// INFO: To test regex, go: https://regex101.com/.
try
{
// NOTE: Null value not allowed. For null strings value objects use StringValueObjectNullable.
value.ThrowIfNull(paramName: _valueName)
.IfShorterThan(_minLength)
.IfLongerThan(_maxLength)
.IfNotMatches(_regex);
}
catch (Exception ex)
{
throw new DomainValidationException(ex.Message, ex);
}
}
/// <inheritdoc />
protected override IEnumerable<object> GetEqualityComponents()
{
yield return Value!; // Null validated.
}
#endregion
}