Date of Birth Value Object 2
Design:


I still think that a DateOfBirth class is too narrow. It should be the name of a property, not a separate class. If you must create a class, create a reusable Date class instead. Enforcing this sort of restrictions at the type level isn't worth the extra work and maintenance cost (in C#). That's my opinion, of course, but judging by your many questions it really is a lot of work, isn't it? ;)
I expect a DateOfBirth.IsValid method to check whether the given input is a valid birth-date. That is, I expect it to reject nonsense input like '-5 45 2018'. However, your implementation enforces a business rule instead. There are several problems with that:


It's confusing: it's basically telling me that '7 februari 2018' is not a valid birthdate.
It's inflexible: what if some logic applies to people above 21, but other logic only to people below 18?

Again, why expose Value directly? As I mentioned before, a date does not have a time component, but by exposing a DateTime property you make it look like it does. Of course, you may want to convert between dates and date-times, but that's what conversion operators are for. A Year, Month and Day property are far more in line with what a date actually is. Look at DateTime, for example: it uses a timestamp as internal storage, but it provides meaningful properties like Year, Month, Day, Hour, Minute, Second, and so on, which results in a much more natural and practically useful interface.
Where did the comparison operators go? Are they superseded by the IsValid method? Or are you planning to use Value for that? If so, why create a separate class in the first place?


Implementation:


No need for == true: IsValid already returns a boolean.
The constructors do not throw if validation fails: they fall back to a 'default' value instead. That's very surprising behavior, in a bad way. It's also inconsistent, because some input does produce an exception. (EDIT: Excuse me, they do throw, because IsValid throws - so that underlines the point below! ThrowIfInvalid would be a more appropriate method name.)
Why does IsValid throw an exception? Its signature suggests that it will only return true/false. Such unexpected behavior makes code more difficult to work with.
The value property can be written more succinctly as public DateTime Value =&gt; _value;, but you could also use a get-only property instead.
You may want to mention which version of C# you're using. I mentioned the a is null improvement from C#7, but I don't see that applied here
so I guess you're still stuck with an older version?


Finally, the == operator can be simplified:

if (ReferenceEquals(a, null) != ReferenceEquals(b, null))
{
    return false;       // One is null, the other is not
}
else if (ReferenceEquals(a, null))
{
    return true;        // Both are null
}
else
{
    return a.Equals(b); // Both are not null
}