Ξέχασες να βάλεις τον κώδικα αλλά δεν πειράζει, υπάρχει και το Reflector

Ξαναξέχασες (όπως και στο StudentGuru) να γράψεις ότι το control είναι για WinForms.
Καταρχήν, δεν υπάρχει κανένας λόγος να φτιάξεις τα δικά σου εικονίδια για το validation καθώς το .NET έχει ήδη το
ErrorProvider control γι αυτόν ακριβώς το λόγο, από την έκδοση 1.1 και μετά. Δεύτερον, το event το οποίο χρησιμοποιείται για validation στα WinForm controls είναι το Validating. Μπορείς να βέβαια να χρησιμοποιήσεις και το TextChanged για να δώσεις feedback την ώρα που γράφει ο χρήστης. Τρίτο και σημαντικότερο, η υλοποίηση του ελέγχου δεν είναι καθόλου αποδοτική - βασικά είναι η πιο αργή υλοποίηση.
Ο αλγόριθμος του check digit λέει χονδρικά ότι παίρνεις κάθε ψηφίο εκτός από το τελευταίο, το κάνεις shift αριστερά τόσες θέσεις όσο και η θέση του, αθροίζεις τα αποτελέσματα και σε αυτά παίρνεις το modulo 11. Αν το αποτέλεσμα είναι 10 επιστρέφεις 0. Στις γλώσσες που δεν έχουν bit shift operators όπως η Visual Basic 6 αντί για shift αριστερά χρησιμοποιούν την ισοδύμανη ύψωση σε δύναμη του δύο. Η διαφορά στην απόδοση όμως είναι δραματική (10 φορές πιο αργό και βάλε) καθώς αντικαθιστάς ένα binary operation που εκτελείται με 1 CPU instruction, σε πράξεις κινητής υποδιαστολής οι οποίες είναι ΠΟΛΥ πιο αργές.
Πέρα από την προφανή αντικατάσταση του Math.Pow με το <<, ο τρόπος με τον οποίο χειρίζεσαι τα ψηφία θέλει αλλαγή. Δεν υπάρχει λόγος να παίρνεις τα ψηφία με Substring και να τα μετατρέπεις με Parse. Ένα string είναι ένα array από Chars και ένα Char μπορείς να το χειριστείς ως Int32 με τιμή τον κωδικό του χαρακτήρα. Για τους αριθμούς ο κωδικός αυτό είναι ίδιος με το ASCII code τους, ξεκινώντας από το 48 για το '0'. Έτσι μπορείς να πάρεις την τιμή του ψηφίου απλά αφαιρώντας 48. Τέλος, ο τρόπος που υπολογίζεις το modulo, (διαίρεση δια έντεκα, πολλαπλασιασμός πηλίκου με 11, αφαίρεση από διαιρετέο) είναι περιττός καθώς όλες οι γλώσσες έχουν modulo operators οι οποίοι είναι πολύ γρηγορότεροι. Στην περίπτωση της C# αυτός είναι το %.
Ο κώδικας σε C# είναι κάπως έτσι:
public bool CheckAFM(string afm)
{
if (afm.Length!=9)
return false;
var digits=afm.ToCharArray();
int checkDigit = digits[8 ]-48;
long sum = ((digits[7] - 48) << 1) +
((digits[6 ] - 48) << 2) +
((digits[5] - 48) << 3) +
((digits[4] - 48) << 4) +
((digits[3] - 48) << 5) +
((digits[2] - 48) << 6) +
((digits[1] - 48) << 7) +
((digits[0] - 48) << 8);
long mod = sum%11;
if (mod == 10)
mod = 0;
return (mod==checkDigit);
}
Ο λόγος που δεν βρίσκεις "κάτι έτοιμο" είναι από τη μία ότι ο αλγόριθμος είναι πολύ απλός για να χρειάζεται εξειδικευμένο control, από την άλλη το validation πρέπει να γίνεται σε πολλαπλά επίπεδα και δεν μπορεί να "δεθεί" με ένα συγκεκριμένο τύπο control όπως το MaskedTextBox. Αν π.χ. εγώ θέλω να χρησιμοποιήσω controls της Telerik ή της DevExpress ένα "έτοιμο" control για ΑΦΜ θα μου είναι άχρηστο.
Παναγιώτης Καναβός, Freelancer
Twitter: http://www.twitter.com/pkanavos