So I have a very simple class with one string as property. This string has to have a certain pattern. I'm trying to enforce this using code contracts. The class looks something like this:
class SimpleClass
{
public Property { get; set; }
public SimpleClass(string prop)
{
Contract.Requires(IsValid(prop));
this.Property = prop;
}
[ContractInvariantMethod]
void ObjectInvariant()
{
Contract.Invariant(IsValid(Property));
}
bool IsValid(string arg)
{
// Use regex to check if arg is a valid string
}
}
Very straightforward. However, this throws an unreadable exception and another one saying that 'Member SimpleClass.IsValid has less visibility than the enclosing method SimpleClass.#ctor(System.String)'. Why is this illegal? Should I copy/paste the regex into both methods? That seems to be the opposite of right. Please help me understand!
Another way is avoid 'primitive obsession' and use a class tailored to your purpose, e.g.:
public SimpleClass(Email address)
{
// no need to check, it must be valid :)
}
... and then encapsulate all your validation logic in the Email class. You'll still have the "string format" issues about validation, but I think a better idiom for this is to create a method called Email.TryParse
, and fashion it along the lines of int.TryParse
.
Just mark IsValid
as public
and you'll be fine. All "components" of a public surface contract have to be public as well, otherwise there is no way for a caller to check that the contract is satisfied.
@AI-CII I understand that, but that would be a design flaw as well, exposing implementation details to consumers.
A contract on a public method is not an implementation detail. A
Contract.Requires
says "hey, I require this to be true for me to do some work for you." If "this" isn't visible to the caller, how can the caller verify that the contract is satisfied?You aren't exposing the implementation details of the method
IsValid
, you are only exposing what must be satisfied for the callee to do its job.
As Jason already stated, Code Contracts requires the method to be public as you already figured out yourself thanks to the exception message.
I understand however that simply making it public doesn't feel right. Perhaps the regex condition can be encapsulated to a static global function of a helper class?
E.g. If it were to check whether a string is a valid URL.
UrlHelper.IsValidUrl( string url )
This interested me so I started doing some googling. There is a solution! Although I would still prefer the helper class with the static method where possible.
It is called Code Contract Abbreviators. You need to include the sourcefile to your project yourself however.
来源:https://stackoverflow.com/questions/5263282/combining-code-contracts-and-regex