I'm trying to create a Required Field Value Object class that will be reusable across Entities in my Domain Model. I'm still learning the C# syntax (been coding in VB.net forever). And I'm all new to DDD (but have at least read several books).
My goal is to design a Value Object called RequiredField<T>
that can accept just about any object (e.g. value type, reference type, or nullable value type (int, string, int?)) which can then be validated before allowing it to become part of an Entity's state. I would use this Value Object any time my entity has a required field (e.g. id, primary key, name, or any other piece of state deemed necessary to have a valid entity). So the Entity will define properties as RequiredField<T>
whenever I have a simple piece of data that is required in order to have a valid Entity.
So I've been fiddling around with this class, and I'm getting closer, but it seems like every time I think I've just about got it, I run in to another stumbling block. Here is what I would like the usage to look like, from my Entity class:
public class PersonEntity
{
public RequiredField<long> ID { get; private set; }
public RequiredField<string> Name { get; private set; }
public RequiredField<DateTime> DOB { get; private set; }
// define other non-required properties ...
public PersonEntity(PersonDTO dto)
{
ID = new RequiredField<long>(dto.ID);
Name = new RequiredField<string>(dto.Name);
DOB = new RequiredField<DateTime>(dto.DOB);
// set other non-required properties ...
}
}
The corresponding DTO that is used to construct the Entity (created in the repository, or application service from the UI, or from a WebService, etc):
public class PersonDTO
{
public long? ID { get; set; }
public string Name { get; set; }
public DateTime? DOB { get; set; }
}
Note that I really desire the ability to have the DTO be just a data bag (that's basically all a DTO is right?). If I don't allow nullable types here, then I have to do validation somewhere else, and the whole point is to let the Value Object in the Entity do the work (right?).
Finally, here is what I have so far on my RequiredField<T>
class. Note that this code doesn't compile.
public class RequiredField<T>
{
private T _value;
public T Value
{
get { return _value; }
set
{
// handle special case of empty string:
if (typeof(T) == typeof(string) && string.IsNullOrWhiteSpace((string)value))
// but (string)value doesn't work: "Can't convert type 'T' to 'string'"
{
throw new ArgumentException("A required string must be supplied.");
}
else if (value == null)
{
throw new ArgumentException("A required field must be supplied.");
}
// also need to handle Nullable<T>, but can't figure out how
else if (Nullable.GetUnderlyingType(typeof(T)) != null)
// need to check value, not T
{
throw new ArgumentException("A required field must be supplied.");
}
_value = value;
}
}
public RequiredField(T value)
{
Value = value;
}
// below is the start of failed attempt to accept a Nullable<T>
// don't like the fact that I have validation going on here AND in the setter
public RequiredField(object value)
{
if (!value.HasValue)
{
throw new ArgumentException("A required field must be supplied.");
}
Value = value.Value;
}
}
So I've gotten myself pretty far into a mess, and I started to question if I'm attempting to do the right thing here. But if I am on a good start, what gets me over the finish line?