Andrei Rinea

.NET Framework & SQL Server

Creating a reusable class - with all the goodies - part 3 : Final analysys

clock September 7, 2009 23:59 by author Andrei Rinea

I've decided to write a class that would model a SSN-like personal identification number used in Romania. It should be useful both in production code and as a learning material for my readers. In the first part I've shown a preliminary analysys and further analysys in the second part.

Validation logic and what interfaces to implement is what is left for this part.

Let's see the fragments that can be validated so we'll see how to model the validation flow. The first digit (the fragments can be seen in the first part) can have values from 1 to 9 so all possible values are valid. Nothing to validate here. The second fragment is the year. Also all possible values (00 to 99) are valid so nothing to validate here.

The fun starts at the next fragment, the month. Only 01 to 12 values are valid anything outside (00, 13, 14, ..., 99) are invalid as they don't represent a valid year. The dating fun gets even hotter at the day. Although 00, 32, 33 and so on values are obviously invalid, some values are valid only in some months or some years.
29th of february is valid in 2008 but not in 2009. 31 is valid in January but not in April. 30 is valid in April but not in February and so on.

Next, the county has a list of predefined values as shown here, in the specs, so their validations should be piece of cake. The Enum.IsDefined (remember from the previous part that I've decided to use an enum for the county) should be a snap :)

The index value must only not be 000 any other value is valid. This brings us to the final check : the check digit. The algorithm is moderately complex (as in not really 1+1 but something close) as seen in the specs :

You take the PNC without the last (check) digit and put it next to the predefined value 279146358279. Next you multiply the first digit of the PNC to be validated to the first digit of this special validation value. Then you store it. Then you take the 2nd digit of your PNC and the 2nd digit of the special value and multiply it and you add it (the product) to the previously stored number and so on until you finish. In the end you have a sum of products that you will modulo by 11 and have a result : for 0..9 this is the final result. For 10 the result will be 1. This is the check digit. Enough theory, let's test it on my PNC :

My PNC :               1810623420056
The validation value : 279146358279
  1. 1 x 2 = 2; Partial-result (PR) : 2
  2. 8 x 7 = 56; PR : 56 + 2 = 58
  3. 1 x 9 = 9; PR : 67
  4. 0 x 1 = 0; PR : 67
  5. 6 x 4 = 24; PR : 91
  6. 2 x 6 = 12; PR : 103
  7. 3 x 3 = 9; PR : 112
  8. 4 x 5 = 20; PR : 132
  9. 2 x 8 = 16; PR : 148
  10. 0 x 2 = 0; PR : 148
  11. 0 x 7 = 0; PR : 148
  12. 5 x 9 = 45; PR : 193

Now 193 % (modulo) 11 = 6 => my check digit is 6. This verifies my full PNC.

As for interfaces to implement there are already-stated interfaces (as shown in the end of part 1) :

  • IEquatable<T> (enables equality comparison to another instance; type-safe)

    NOTE : Here type safe means the comparand is forced to be of the same type whereas in the type-unsafe versions the comparand is of type System.Object from which all classes inherit in .NET which allows invalid type instances to be passed in - these are required to work with old components and classes.
  • IComparable (enables value comparison to another instance; type-unsafe)
  • IComparable<T> (enables value comparison to another instance; type-safe)
  • IConvertible (enables converting to many basic types)
  • ICloneable; I thought of this later - after the initial analysys (enables deep cloning of the instance)

There are also interfaces necessary to improve the serialization performance (speed and memory) :

In the end, the IsValid and Violations properties should be grouped into a IValidable<T> interface that I'll define right now :

interface IValidable<TFieldEnum> where TFieldEnum : struct
{
    bool IsValid { get; }
    KeyValuePair<TFieldEnum, string>[] Violations { get; }
}

In the next part we'll FINALLY begin writing some code :)

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Creating a reusable class - with all the goodies - part 1 : Preliminary analysys

clock September 7, 2009 22:22 by author Andrei Rinea

I always wanted to build a class that could have some value in the real life and that could serve as an example for some (good) practices. It seems that I have the opportunity right now.

In every country, mine included, there is some sort of identification number, unique for all its citizens. In the US there is the SSN and in Romania there is a PNC (CNP spelled in romanian) which stands for Personal Numeric Code. 

Some applications (web sites and other kinds) may require you, at some point, to specify a valid PNC. These apps usually validate it (lightly most of them) and none of them I've seen to take advantage of the info the PNC conveys for pre-filling certain fields. This sparked me the idea to write a dedicated class for this.

The specifications for this romanian SSN (the PNC) can be found on Wikipedia : translated to english version and romanian (original version).

In short there are 13 digits like so :

S YY MM DD CC III X

S represents the sex and the century of the birth date. Odd digits for males and even digits for females. 1 and 2 for 20th century, 3 and 4 for 19th century, 5 and 6 for 21st century, 7 and 8 for resident foreigners and 9 for non-resident foreigners
YY represents the two-digit version of the birth date's year
MM the same for the month
DD the same for the day of the month
CC represents the two-digit code of the county of birth
III represents an index number - unique per county per day
and finally
X represents the check digit

Not very complicated, isn't it? Let's take mine for example :

1810623420056

So:

  1. I am a male, born in the 20th century (1)
  2. I was born in 1981
  3. .. in June
  4. on the 23rd day
  5. in the 42 county (that is Bucharest, 2nd district)
  6. The fifth in the birth center
  7. and the check digit is 6

What I would like from a class that models this entity :

  • To have a parameterless (default constructor) so it can be easily serializable
  • To not throw exceptions in the other constructors if the data is bogus but rather to sum up a list of violations (for example the day is 32)
  • To be bind friendly in Winforms, WPF, ASP.NET Web forms and ASP.NET MVC
  • To expose a read/write property (we'll call it "Value") to enable easy binding with the ASP.NET MVC's default binder
  • The XML serialization should take minimal space (only relevant data should be serialized and elements and attributes should have short names - but still understandable)
  • The same for binary serialization
  • It should implement IConvertible so the class users should have minimal effort in converting it to/from other types
  • It should implement IEquatable and IEquatable<T> so it is easy for one to compare two instances
  • Similar thing for IComparable so sorting should be fast and efficient
  • There should be a compact form so large collections could be marshalled efficiently even over slow channels
  • Last but not least it should provide (a) static method(s) to generate random values

There's a long list of requirements... let's see how we'll manage over the course of the next parts :)

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


About me

A passionated .NET Developer working closely with Microsoft technologies. View my public site.

Page List

Sign in