I have a 'Validator' class that needs to do some simple validation. However, there are some instances where all or just a single method may need to be called.
The interface for the validator is defined as:
internal interface IBrandValidator
{
BrandInfo ValidateBrands();
}
The class definition for the object being returned:
internal class BrandInfo
{
public Organisation Brand { get; set; }
public Client Client { get; set; }
public Location Location { get; set; }
public Language Language { get; set; }
}
The class that implements this interface:
internal class ClientValidator : IBrandValidator
{
private readonly int? clientId;
private readonly int? locationId;
private readonly int? languageId;
public ClientValidator(int clientId, int? locationId, int? languageId)
{
this.clientId = clientId;
this.locationId = locationId;
this.languageId = languageId;
}
public BrandInfo ValidateBrandDimensions()
{
var brandInfo= new BrandInfo();
//Optional validation
if(client != null)
brandDimensions.Client = ValidateClient(clientId);
if(locationId != null)
brandDimensions.Location = ValidateLocation(locationId);
if(languageId != null)
brandDimensions.Language = ValidateLanguage(languageId);
return brandInfo;
}
}
My question is. The 3 validation methods under the comment 'Optional Validation'. May or may not need to be called. However, there may be additional things I need to validate in future and using the nullable int with the if statement is a bad route.
Is there a design pattern I can implement to achieve something similar?
Your code is hardly predictable by reading for example:
brandDimensions.Client = ValidateClient(clientId);
ValidateClient should return truthy or falsy object. But is assigned to an Object with name "Client".
Your validator returns an BrandInfo Object. But does not include any property or method which indicates if it is valid or not ?!?
The ClientValidator does not have to validate for a client - because it is nullable?
It think you should consider to reorganize part of your codes.
If a class creates many objects from an Identifier you could probably use the Factory Pattern.
If you want to validate a complex object name it after ComplexObjectValidator.
Every part of the complex object gets validated.
If it is valid that for example an Id is nullable put that check in the Validator Implementation.
It is hard to tell more specifics because it is unclear what your code does or intends to do.
Edit:
As rule of thumb:
Truthy or falsy Methods: Prefix with "Is" "Must" "Should" "Has" "Can" etc.
If a method should return an Object: "GetValidatedClient" "ValidateAndReturnClient" "CreateClient"
So someone reading your code which can be you in the future (6 months, 3 years, 10 years) can just infer the behaviour from your function names.
ValidateClient would imply that it is just Validating. More specifically it just returns void. Because it just Validates. If it returns truthy or falsy values use one of the prefixes listed above. If it returns an Validator Object use "GetValidationResultFor(xyz)" for example.
Related
I have requirement in a custom class where I want to make one of my properties required.
How can I make the following property required?
public string DocumentType
{
get
{
return _documentType;
}
set
{
_documentType = value;
}
}
If you mean "the user must specify a value", then force it via the constructor:
public YourType(string documentType) {
DocumentType = documentType; // TODO validation; can it be null? blank?
}
public string DocumentType {get;private set;}
Now you can't create an instance without specifying the document type, and it can't be removed after that time. You could also allow the set but validate:
public YourType(string documentType) {
DocumentType = documentType;
}
private string documentType;
public string DocumentType {
get { return documentType; }
set {
// TODO: validate
documentType = value;
}
}
.NET 7 or newer
Syntax
public class MyClass
{
public required string Name { get; init; }
}
new MyClass(); // illegal
new MyClass { Name = "Me" }; // works fine
Remarks
The required properties must declare a setter (either init or set).
Access modifiers on properties or setters cannot be less visible than their containing type, as they would make impossible to initialize the class in some cases.
public class MyClass
{
internal required string Name { get; set; } // illegal
}
Documentation
Official documentation here
Feature demo here
.NET 6 or older
See this answer
If you mean you want it always to have been given a value by the client code, then your best bet is to require it as a parameter in the constructor:
class SomeClass
{
private string _documentType;
public string DocumentType
{
get
{
return _documentType;
}
set
{
_documentType = value;
}
}
public SomeClass(string documentType)
{
DocumentType = documentType;
}
}
You can do your validation – if you need it – either in the property's set accessor body or in the constructor.
With the release of .NET 7 and C# 11 in November 2022 you can now use the required modifier this way:
public class Person
{
public Person() { }
[SetsRequiredMembers]
public Person(string firstName) => FirstName = firstName;
public required string FirstName { get; init; }
public int Age { get; set; }
}
And when you don't have the required properties it will throw an error when you try to initialize an object.
For more information refer to:
https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#required-members
https://learn.microsoft.com/en-us/dotnet/csharp/properties#init-only
Add a required attribute to the property
Required(ErrorMessage = "DocumentTypeis required.")]
public string DocumentType
{
get
{
return _documentType;
}
set
{
_documentType = value;
}
}
For custom attribute detail Click Here
I used an other solution, not exactly what you want, but worked for me fine because I declare the object first and based on specific situation I have different values. I didnt want to use the constructor because I then had to use dummy data.
My solution was to create Private Sets on the class (public get) and you can only set the values on the object by methods. For example:
public void SetObject(string mandatory, string mandatory2, string optional = "", string optional2 = "")
This one liner works in C# 9:
public record Document(string DocumentType);
new Document(); // compiler error
new Document("csv"); // correct way to construct with required parameter
This explains how it works. In the above code, Document is the name of the class or "record". That first line of code actually defines an entire class. In addition to this solution essentially making a required DocumentType property (required by an auto implemented constructor), because it uses records, there are additional implications. So this may not always be an appropriate solution, and the C# 11 required keyword will still come in handy at times. Just using record types doesn't automatically make properties required. The above code is a special syntax way of using records that essentially has this effect as well as making the property init only and causes a deconstructor to be automatically implemented.
A better example would be using an int property instead of a string since a string could still be empty. Unfortunately I don't know of any good way to do extra validation within the record to make sure the string is not empty or an int is in range, etc. You would have to go deeper down the TOP (type driven development) rabbit hole, which may not be a bad thing. You could create your own type that doesn't allow empty strings or integers outside your accepted range. Unfortunately such an approach would lead to runtime discovery of invalid input instead of compile time. There might be a better way using static analysis and metadata, but I've been away from C# for too long to know anything about that.
Say I have this class with a few members, for example (this is a contrived example, I'd rather no have a discussion about the intricacies of the real-life design. I really just want to convey the general idea here.):
public class Address
{
public Guid Id { get; set; }
public Guid? HouseId { get; set; }
public Guid? FlatId { get; set; }
public Guid? SomeOtherBuildingTypeId { get; set;
}
Now as it happens there exist 3 methods to create an Address:
public void CreateAddressForHouse();
public void CreateAddressForFlat();
public void CreateAddressForSomeOtherBuildingType();
Under the surface this group of methods does the exact same thing, bar setting a different Id property in the Address class. This is causing quite some code duplication in the real life application and I want to rewrite this to something more general.
In my mind I can pass the name of the required property and its value to a CreateAddress function, in something like a Func. But I'm seriously lacking in this respect, where to start? What .NET stuff can I use out of the box? Or what specific keywords should I look for?
You can use a MemberExpression:
public void CreateAddress(Expression<Func<Address, Guid?>> member)
{
// Get the property from the expression
var propertyInfo = GetPropertyInfo(this, member);
// Create a new address
var guid = Guid.NewGuid();
// Assign it to the property of this instance
propertyInfo.SetValue(this, guid);
}
Then you call the method like this, using a lambda a => a.PropertyName:
var address = new Address();
address.CreateAddress(a => a.HouseId);
Console.WriteLine(address.HouseId);
See Retrieving Property name from lambda expression for the implementation of GetPropertyInfo. It gets the PropertyInfo of the member specified in the lambda expression (and checks that it is indeed a property), which you can use to set the property in the CreateAddress method.
Apart from that, #Corak's suggestion is a valid one. Maybe you shouldn't use a property per address type, but use a Dictionary<AddressType, Guid?> property. That may or may not be viable depending on the class design and its intended usage.
You can use expression trees to simplify your problem:
public class AddressService
{
public Address CreateAddress(Expression<Func<Address, Guid?>> idPropertySelector)
{
// So you get the property info to later set it using reflection
MemberExpression propertyExpr = (MemberExpression)idPropertySelector.Body;
PropertyInfo property = (PropertyInfo)propertyExpr.Member;
// Then you create an instance of address...
Address address = new Address();
// and you set the property using reflection:
property.SetValue(address, (Guid?)Guid.NewGuid());
return address;
}
}
Now, who knows where in your code, this will work:
AddressService service = new AddressService();
Address address = service.CreateAddress(a => a.FlatId);
Guid? flatId = address.FlatId; // This will be already assigned!
You can add a property BuildingType BuildingType being a value of the enum BuildingType { House, Flat, SomeOtherBuildingType, YetAnotherThing } as suggested by Corak.
To make it simpler, you can create a parameterized constructor in Address class:
public Address(Guid? id,BuildingType type)
{
switch(type)
{
case BuildingType.House:
HouseId=id;
break;
case BuildingType.Flat:
FlatId=id;
break;
case BuildingType.SomeOtherBuildingType:
SomeOtherBuildingTypeId =id;
break;
default:
break;
}
}
This way it will be easier to extend.
Also, you need not to have so many methods. Only one CreateAddress() can be used to generate address of multiple types.
I have data from multiple organisations (police, fire, office) that need output in different formats.
To achieve this, I defined the following (this is a little simplified):
Transaction class -
"Success" indicator - Boolean.
"Type of department"- String or Enum.
A class which can be of any type - Police, Fire or Office (My question is on this as you will see).
A GenerateOutput() method - to handle generation of file formats.
Police class
Age - String
VehicleNumber - Integer
Supervisor - String
Fire class
Name - String
FireEngineNumber - Integer
County - Enum
WorkTimings - Enum
Office Class
Age - String
DeskNumber - Integer
Department - String
PayScale - Enum
IsManagement - Bool
As you can see, the Police, Fire and Office classes dont share anything in common and are primarily intended as data carrying entities. I intend to use a Factory to return an appropriate generic (not a C# generic) Transaction object with the data (Transaction object with Police, Fire or Office data within it) and then pass the returned object to a Strategy pattern which determines the file format (CSV, Excel, or XML; specified in a configuration file) each one needs.
My problem is in the definition of the Transaction object.
What type does the class in "3." of the Transaction class need to be? The data for each org differs, there are no common members, I am unable to define a common class for all.
Is the overall design appropriate? What other designs should I consider?
Based on Peter's comments below:
I think using generics might work, I ran into a problem though. I would like to use a factory to return the object requested, using GetTransactionObject, as below. What should be the return type of GetTransactionObject to accomodate this.
class TransactionFactory
{
Dictionary<string, Type> typeClassLookup;
public TransactionFactory()
{
typeClassLookup = new Dictionary<string, Type>();
typeClassLookup.Add("Police", typeof(PoliceData));
typeClassLookup.Add("Fire", typeof(FireData));
}
Transaction<????> GetTransactionObject(string org)
{
if( typeClassLookup.TryGetValue(org, out typeValue))
{
switch (typeValue.ToString())
{
case "policeData":
transactionObject = new Transaction<PoliceData>() { Data = new PoliceData(), params = null};
case "FireData":
transactionObject = new Transaction<FireData>() {Data = new FireData(), params = null};
}
}
return transactionObject;
If the types really have nothing in common, then you need no explicit base class. System.Object suffices, just as with many other generic types (i.e. any generic type lacking a constraint).
In other words, you could declare as:
class Transaction<T>
{
public bool Success { get; private set; }
public T Entity { get; private set; }
public Transaction(bool success, T entity)
{
Success = success;
Entity = entity;
}
public void GenerateOutput() { /* something goes here */ }
}
Personally, I would avoid adding a "department type" member. After all, that's implicit from the type parameter T. But you could add that easily to the above if you want.
If and when you find that the types do have something in common, such that your Transaction<T> type needs to do more than simply hold onto an instance of one of those types (which is about all it can do without a constraint), then you will be able to put that commonality into an interface or base class (depending on the specific need), and specify that in a constraint for the Transaction<T> class.
Note that it's not clear what you mean for the GenerateOutput() to do, or how it should work. But assuming that you want output that is specific for each Entity value, it seems to me that that is your "something in common". I.e., it's not the Transaction<T> class at all that needs to implement that method, but rather each entity type. In that case, you have something like this:
interface IDepartmentEntity
{
void GenerateOutput();
}
class Office : IDepartmentEntity
{
public void GenerateOutput() { /* department-specific logic here */ }
}
// etc.
Then you can declare:
class Transaction<T> where T : IDepartmentEntity
{
public bool Success { get; private set; }
public T Entity { get; private set; }
public Transaction(bool success, T entity)
{
Success = success;
Entity = entity;
}
public void GenerateOutput() { Entity.GenerateOutput(); }
}
EDIT:
Per Prasant's follow-up edit, with a request for advice on the GetTransactionObject()…
The right way to do this depends on the caller and the context, a detail not provided in the question. IMHO, the best scenario is where the caller is aware of the type. This allows the full power of generics to be used.
For example:
class TransactionFactory
{
public Transaction<T> GetTransactionObject<T>()
where T : IDepartmentEntity, new()
{
return new Transaction<T>()
{
Data = new T(),
params = null
}
}
}
Then you call like this:
Transaction<FireData> transaction = factory.GetTransactionObject<FireData>();
The caller, of course already knowing the type it is creating, then can fill in the appropriate properties of the transaction.Data object.
If that approach is not possible, then you will need for Transaction<T> itself to have a base class, or implement an interface. Note that in my original example, the IDepartmentEntity interface has only one method, and it's the same as the GenerateOutput() method in the Transaction class.
So maybe, that interface is really about generating output instead of being a data entity. Call it, instead of IDepartmentEntity, something like IOutputGenerator.
In that case, you might have something like this:
class Transaction<T> : IOutputGenerator
{
// all as before
}
class TransactionFactory
{
public IOutputGenerator GetTransactionObject(string org)
{
if( typeClassLookup.TryGetValue(org, out typeValue))
{
switch (typeValue.ToString())
{
case "policeData":
transactionObject = new Transaction<PoliceData>() { Data = new PoliceData(), params = null};
case "FireData":
transactionObject = new Transaction<FireData>() {Data = new FireData(), params = null};
}
}
return transactionObject;
}
}
This is an inferior solution, as it means the caller can only directly access the IOutputGenerator functionality. Anything else requires doing some type-checking and special-case code, something that really ought to be avoided whenever possible.
Note: if the Transaction type has other members which, like the GenerateOutput() method, are independent of the contained type T here, and which would be useful to callers who don't know T, then a possible variation of the above is to not reuse the interface used for the department-specific data types, but instead declare a base class for Transaction<T>, named of course Transaction, containing all those members not related to T. Then the return value can be Transaction.
What type does the class in "3." of the Transaction class need to be?
To decouple your department classes from the various export types, I recommend you make the department classes implement a common interface. Something like this:
public interface Exportable {
// return a list of attribute names, values, and types to export
IList<Tuple<String, String, Type>> GetAttributes();
}
For example:
public class Police : Exportable {
public IList<Tuple<String, String, Type>> GetAttributes() {
// return list size 3 - attribute info for Age, VehicleNumber, Supervisor
}
}
Is the overall design appropriate? What other designs should I consider?
The Transaction class design doesn't seem well suited for this problem.
Consider an Export class with a method for each export type, each method which receives the attributes returned from the Exportable interface method. Basic outline:
public static class Export {
public static boolean CSV(IList<Tuple<String, String, Type>> attributes) {
// export attributes to CSV, return whether succeeded
}
public static boolean Excel(IList<Tuple<String, String, Type>> attributes) {
// export attributes to Excel, return whether succeeded
}
// same thing for XML
}
I have an attribute that I am using to decorate object properties with. The attribute identifies the properties as needing validation to be performed on them. I am essentially implementing the Strategy Pattern and building all of the validation (really only about 6 types) in to individual objects that I can use across multiple classes. What I want to do, is provide parameters to the validation classes, without having to create an attribute for each validation object variation.
My attribute looks like this:
[AttributeUsage(AttributeTargets.Property)]
public class ValidationRuleAttribute : Attribute
{
public ValidationRuleAttribute(Type validationRule, string customFailureMessage = "")
{
if (typeof(IValidationRule).IsAssignableFrom(validationRule))
{
this.ValidationRule = string.IsNullOrEmpty(customFailureMessage)
? Activator.CreateInstance(validationRule, customFailureMessage) as IValidationRule
: Activator.CreateInstance(validationRule) as IValidationRule;
}
else
{
throw new ArgumentException(
string.Format(
"ValidationRule attributes can only be used with IValidationRule implementations. The '{0}' Tyoe is not supported.",
validationRule.Name));
}
}
public IValidationRule ValidationRule { get; private set; }
}
As an example, I have a simple StringIsNotNull validation object. I want to expand on it by allowing me to specify a minimum string length requirement. So the StringIsNotEmptyValidation would become StringHasMinimumLengthValidation
public class StringIsNotEmptyValidation : IValidationRule
{
private readonly string customErrorMessage;
public StringIsNotEmptyValidation()
{
}
public StringIsNotEmptyValidation(string customErrorMessage)
{
this.customErrorMessage = customErrorMessage;
}
public string ResultMessage { get; private set; }
public IValidationMessage Validate(System.Reflection.PropertyInfo property, IValidatable sender)
{
string value = property.GetValue(sender).ToString();
// Validate
bool isFailed = string.IsNullOrWhiteSpace(value);
if (isFailed)
{
if (string.IsNullOrEmpty(this.customErrorMessage))
{
DisplayNameAttribute displayName = property.GetCustomAttribute<DisplayNameAttribute>(true);
string errorMessage = displayName == null
? string.Format("You can not leave {0} empty.", property.Name)
: string.Format("You can not leave {0} empty.", displayName.DisplayName);
this.ResultMessage = errorMessage;
return new ValidationErrorMessage(errorMessage);
}
else
{
this.ResultMessage = this.customErrorMessage;
return new ValidationErrorMessage(customErrorMessage);
}
}
this.ResultMessage = string.Empty;
return null;
}
}
Within my model, I decorate my property with the attribute and validation object.
[RepositoryParameter(DbType.String)]
[ValidationRule(typeof(StringIsNotEmptyValidation))]
public string WorkDescription
{
get
{
return this.workDescription ?? string.Empty;
}
set
{
this.SetPropertyByReference(ref this.workDescription, value);
if (this.HasValidationMessageType<ValidationErrorMessage>(this.GetPropertyName(p => p.WorkDescription)))
{
this.Validate();
}
}
}
What I want to do, is write my attribute usage like this:
[ValidationRule(new StringIsNotEmptyValidation(minimumLength: 4))]
Since you can't instance objects in an attribute constructor, I'm forced to provide the attributes in my attribute constructor like this:
[ValidationRule(typeof(StringIsNotEmptyValidation), minLength: 4)]
I don't like this because if I have a ObjectIsNotNull or a StringIsInRange I will need to do two things:
Create a new attribute for each parameter variation (or a lot of overloads)
Set up the validation rule instances within the constructor, which will have varying property names.
The Validation object implements the following interface
public interface IValidationRule
{
string ResultMessage { get; }
IValidationMessage Validate(PropertyInfo property, IValidatable sender);
}
I don't want to bloat my interface with a large number of properties that might be used or might not be used depending on the Rule implementing it. It also makes it difficult to assign attribute params to the rule object.
So my question is how can I provide parameters to the IValidationRule concrete classes, without creating multiple attribute types to facilitate this? This is being used so that I an do cross-object validation. The PropertyInfo passed in to the validation rule is from a cache of PropertyInfo's. I need to keep the amount of reflection used down, otherwise I'd just use attributes for each rule parameter and use reflection on sender to figure out what ranges to use.
Update
After discussing this with Corey, it does indeed appear that attributes are supported in Universal Apps and it is only the DataAnnotations namespace that is missing. In order to get access to the attributes, I had to add a using statement to System.Reflection in order to gain access to a series of extension methods that expose the GetCustomAttribute methods. They are now extension methods and not built in to the Type class.
So I suppose in the end, I can just create my validation logic within the attributes, instead of individual objects. I can't think of any downsides to going this route.
In order to access the attributes in a Universal App, you have to include System.Reflection as a using statement, then access via the GetRuntimeProperties() extension method.
var validationRule = this
.GetType()
.GetRuntimeProperties() // Can be GetRuntimeFields or GetRuntimeMethods as well.
.FirstOrDefault(p => p.GetCustomAttribute<IntegerInRangeAttribute>() != null);
So there are a few options here.
First, and often used, is to have a different attribute for each type of rule you want to process. You are already building classes for each of your rules, so instead of having some encapsulating attribute that instantiates them all just make each rule an attribute:
[StringMinLengthRule(5)]
public string SomeString { get; set; }
Build the validation logic into your attributes - say with a base attribute that does the bulk of the work, calling a virtual method to do the actual validation. Then you can just enumerate the rule attributes and call them from your validation method.
Next, you can have a number of different properties on your attribute that can be set during declaration to provide the properties for your various rules:
[Validation(RuleType.StringMinLength, MinLength = 5)]
public string SomeString { get; set; }
You could still have the rules be processed in the ValidationAttribute itself, or create IValidationRule instances at run-time to process the actual validations. Unfortunately there's nothing to stop you from adding a Validation attribute that sets the wrong properties for the rule type, resulting in errors at run-time when you try to validate an instance.
Finally, something that works but probably shouldn't... and it's kinda ugly:
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class ValidationRuleAttribute : Attribute
{
public IValidationRule ValidationRule { get; private set; }
public ValidationRuleAttribute(RuleType type, params object[] parms)
{
if (type == RuleType.NotNull)
{
if (parms.Length != 0)
throw new ArgumentException("RuleType.NotNull requires 0 parameters", "parms");
ValidationRule = new NotNullValidation();
}
if (type == RuleType.StringMinLength)
{
if (parms.Length != 1)
throw new ArgumentException("RuleType.StringMinLength requires 1 parameter", "parms");
if (!(parms[0] is int))
throw new ArgumentException("RuleType.StringMinLength requires an integer", "parms");
ValidationRule = new StringLengthValidation((int)parms[0]);
}
}
}
The biggest problem with it is that it won't complain until you try to instantiate a class at run-time that has a bad Validation attribute. Your code can run quite happily up until the point where it tries to create an instance of that bad class, at which point all of the attributes will actually be constructed and those ArgumentExceptions start flying.
In fact only the first option doesn't suffer from run-time problems, because you can control the types of parameters being supplied by using the correct constructor formats. You can still tell it to do silly things - like requiring that strings must have less than 0 length for instance - but that's up to you :P
I have a persistence ignorant domain model that uses abstract repositories to load domain objects.
The concrete implementation of my repositories (the data access layer (DAL)) uses entity framework to fetch data from a sql server database.
The database has length constraints on a lot of its varchar columns.
Now imagine that I have the following domain class:
public class Case
{
public Case(int id, string text)
{
this.Id = id;
this.Text = text;
}
public int Id { get; private set; }
public string Text { get; set; }
}
And an abstract repository defined as follows:
public abstract class CaseRepository
{
public abstract void CreateCase(Case item);
public abstract Case GetCaseById(int id);
}
The [text] column of the table in sqlserver is defined as nvarchar(100)
Now I know that I mentioned that my domain class (Case) was persistence ignorant, nevertheless I feel that it is wrong that it allows
for values of the text parameter that cannot ultimately be saved by my concrete repository implementation because the entity framework
will throw an exception when assigning the text property to the entity framework generated class when it is longer than 100 characters.
So I have decided that I wish to check this constraint in the domain model, because this allows me to check data validity before attempting to
pass it on to the DAL, and thus making error reporting more centric to the domain object. I guess you could argue that I could just check the
constraint in my constructor and in the property setter, but since I have hundreds of classes that all have similar constraints I wanted a
more generic way to solve the problem
Now, the thing that I've come up with is a class called ConstrainedString, defined as follows:
public abstract class ConstrainedString
{
private string textValue;
public ConstrainedString(uint maxLength, string textValue)
{
if (textValue == null) throw new ArgumentNullException("textValue");
if (textValue.Length > maxLength)
throw new ArgumentException("textValue may not be longer than maxLength", "textValue");
this.textValue = textValue;
this.MaxLength = maxLength;
}
public uint MaxLength { get; private set; }
public string Value
{
get
{
return this.textValue;
}
set
{
if (value == null)
throw new ArgumentNullException("value");
if (value.Length > this.MaxLength) throw new ArgumentException("value cannot be longer than MaxLength", "value");
this.textValue = value;
}
}
}
Furthermore I have an implementation of ConstrainedString called String100 :
public class String100 : ConstrainedString
{
public String100(string textValue) : base(100, textValue) { }
}
Thus leading to a different implementation of Case that would look like this:
public class Case
{
public Case(int id, String100 text)
{
this.Id = id;
this.Text = text;
}
public int Id { get; private set; }
public String100 Text { get; set; }
}
Now, my question is; Am I overlooking some built-in classes or some other approach that I could use instead? Or is this a reasonable approach?
Any comments and suggestions are most welcome.
Thank you in advance
I believe your validation should reside in your domain model. The constraints on your fields directly represent some business logic. Ultimately you have to validate before you persist anyway.
I think this depends on many factors (as well as some personal preferences). Sometimes the constraint should form part of the domain object - for example with social security numbers/passport numbers... - these normally have a fixed length and cannot vary as a domain rule - not a data persistence rule (although you might constrain the db as well).
Some prefer to not have these sort of checks in their domain model and instead have something like a validation attribute on the property that can be inspected and executed external from the domain object by a seperate validator.
The issue you might have with your method (although not difficult to get around) is getting any ORM/Mapper - if you're using one - to know how to map a string to/from the db to your ConstrainedString.
The ConstrainedString might not get around the issue of the domain object having extra info about the constraint as it might need to construct the ConstrainedString
If you change the constraints of a Case, it makes sense that you'd have to make a new one - you've changed the contract, and old code will no longer know if it's meeting the requirements or not.
Instead of worrying about what your repository will or will not allow, define what you will allow in your class, and make sure that you find a way to work with any repository that you change to in the future. You own your API - your dependencies do not.