Author Topic: How to validate a property of a struct ?  (Read 5929 times)

0 Members and 1 Guest are viewing this topic.

Grrr1337

  • Swamp Rat
  • Posts: 812
How to validate a property of a struct ?
« on: January 05, 2019, 07:13:32 PM »
Hey .NET guys, I have a simple question and can't seem to find a simple anwer..
Is there a way to validate the property value of a struct ?

Example:
Code - C#: [Select]
  1. class Program
  2. {
  3.     void test()
  4.     {
  5.         TrueColor MyColor;
  6.         MyColor.Red = 212;
  7.         MyColor.Green = 152;
  8.         MyColor.Blue = 314; // <- invalid asignment
  9.     }
  10. }
  11.  
  12. struct TrueColor
  13. { // can these properties be in the range of 0-255 ?
  14.     public int Red;
  15.     public int Green;
  16.     public int Blue;
  17. }
(apply ''((a b c)(a b c))
  '(
    (( f L ) (apply 'strcat (f L)))
    (( L ) (if L (cons (chr (car L)) (f (cdr L)))))
    (72 101 108 108 111 32 87 111 114 108 100)
  )
)
vevo.bg

MickD

  • King Gator
  • Posts: 3619
  • (x-in)->[process]->(y-out) ... simples!
Re: How to validate a property of a struct ?
« Reply #1 on: January 05, 2019, 07:48:04 PM »
The best way to do this is by creating a 'ColorValue' class.

something like this
Code - C#: [Select]
  1. class ColorValue{
  2.     private int _value;
  3.  
  4.     public int Value{
  5.         get {
  6.             return _value;
  7.         }
  8.         set {
  9.             if (value > 255){
  10.                 // cap it and continue (or throw exception?):
  11.                 _value = 255;
  12.             }
  13.             else if (value < 0){
  14.                 _value = 0;
  15.             } else {
  16.                 _value = value;
  17.             }
  18.         }
  19.     }
  20. }
  21.  

It's deemed good practice wrap a primitive type like this when you would use it as a 'type' in your program and only use primitive types like int, string etc within methods for calculations (within a small scope and not public throughout your app).
You may also need to write ToString() and other interface methods etc as needed.
« Last Edit: January 05, 2019, 07:55:11 PM by MickD »
"Short cuts make long delays,' argued Pippin.”
J.R.R. Tolkien

kdub_nz

  • Mesozoic keyThumper
  • SuperMod
  • Water Moccasin
  • Posts: 2121
  • class keyThumper<T>:ILazy<T>
Re: How to validate a property of a struct ?
« Reply #2 on: January 05, 2019, 08:04:11 PM »
Could you just define the properties as byte ( Unsigned 8-bit integer ) ?
Called Kerry in my other life
Retired; but they dragged me back in !

I live at UTC + 13.00

---
some people complain about loading the dishwasher.
Sometimes the question is more important than the answer.

MickD

  • King Gator
  • Posts: 3619
  • (x-in)->[process]->(y-out) ... simples!
Re: How to validate a property of a struct ?
« Reply #3 on: January 05, 2019, 08:13:44 PM »
Could you just define the properties as byte ( Unsigned 8-bit integer ) ?

good point, would that truncate the value on both sides or throw an exception at runtime? For example, if a user enters a larger value at a prompt?
"Short cuts make long delays,' argued Pippin.”
J.R.R. Tolkien

kdub_nz

  • Mesozoic keyThumper
  • SuperMod
  • Water Moccasin
  • Posts: 2121
  • class keyThumper<T>:ILazy<T>
Re: How to validate a property of a struct ?
« Reply #4 on: January 05, 2019, 08:20:44 PM »
If it's a user prompt I'd use
Code - C#: [Select]
  1. byte.tryParse()
Called Kerry in my other life
Retired; but they dragged me back in !

I live at UTC + 13.00

---
some people complain about loading the dishwasher.
Sometimes the question is more important than the answer.

kdub_nz

  • Mesozoic keyThumper
  • SuperMod
  • Water Moccasin
  • Posts: 2121
  • class keyThumper<T>:ILazy<T>
Re: How to validate a property of a struct ?
« Reply #5 on: January 05, 2019, 08:36:20 PM »
Called Kerry in my other life
Retired; but they dragged me back in !

I live at UTC + 13.00

---
some people complain about loading the dishwasher.
Sometimes the question is more important than the answer.

MickD

  • King Gator
  • Posts: 3619
  • (x-in)->[process]->(y-out) ... simples!
Re: How to validate a property of a struct ?
« Reply #6 on: January 05, 2019, 08:44:36 PM »
I guess it depends on the context, for a colour value like this I'd just cap it at either end as the end result won't make much if any difference to the final colour and avoids a lot of unnecessary boiler plate to handle exceptions. Any value greater than 255 for Red won't make it any red-er :)
"Short cuts make long delays,' argued Pippin.”
J.R.R. Tolkien

kdub_nz

  • Mesozoic keyThumper
  • SuperMod
  • Water Moccasin
  • Posts: 2121
  • class keyThumper<T>:ILazy<T>
Re: How to validate a property of a struct ?
« Reply #7 on: January 05, 2019, 11:39:04 PM »
casting an  int (which happens to have a calculated value of 330) to a byte may give a result not expected

ie results in a .Red value of 74

added:
I s'pose at the end of the day "it all depends"
« Last Edit: January 05, 2019, 11:46:10 PM by kdub »
Called Kerry in my other life
Retired; but they dragged me back in !

I live at UTC + 13.00

---
some people complain about loading the dishwasher.
Sometimes the question is more important than the answer.

Grrr1337

  • Swamp Rat
  • Posts: 812
Re: How to validate a property of a struct ?
« Reply #8 on: January 06, 2019, 12:11:50 PM »
The best way to do this is by creating a 'ColorValue' class.

something like this
Code - C#: [Select]
  1. class ColorValue{..}
  2.  

It's deemed good practice wrap a primitive type like this when you would use it as a 'type' in your program and only use primitive types like int, string etc within methods for calculations (within a small scope and not public throughout your app).
You may also need to write ToString() and other interface methods etc as needed.

Thanks Mike!
Was looking exactly how it should be done.. since int is a non-nullable type, the compiler throws error if I try to set the int property to null.
Maybe instead of throwing an exception when the value is out of range, perhaps in this case would be more appropriate to return a negative int value?
Although the best behaviour would be to "throw an exception at runtime", like you mentioned in your next post. :)
BTW your example works fine even if it was defined as struct instead of class.


Could you just define the properties as byte ( Unsigned 8-bit integer ) ?

Thanks kdub, byte worked perfectly for this case -

Code - C#: [Select]
  1. struct TrueColor
  2. {
  3.   public byte Red;
  4.   public byte Green;
  5.   public byte Blue;
  6. }


Could you just define the properties as byte ( Unsigned 8-bit integer ) ?

good point, would that truncate the value on both sides or throw an exception at runtime? For example, if a user enters a larger value at a prompt?

Would be nice if there was a runtime validation, upon a custom criteria - like in your example from reply #1.
Although even if it was possible, the compiler would be able to validate it only on a constant variable (because the value would be predefined) and not on an user input like Console.ReadLine();

My question started upon exploring structs more carefuly, before I was just using classes with properties and constructors.
But realised that instead of defining 5-6 Constructors to validate (all or some of) the properties, I could just use a struct, so I remembered John's cow
The problem was I didn't knew how to validate within the property (without a constructor).. in order to apply a range to the cow's weight.
But now I know, thanks to Mike's replly!


I was attempting to solve this exercise #12 from here, where the validation steps into the next level (having an unique ID for every employee)
Quote
12. A company dealing with marketing wants to keep a data record of its employees.
Each record should have the following characteristic – first name, last name, age, gender (‘m’ or ‘f’) and unique employee number (27560000 to 27569999).
Declare appropriate variables needed to maintain the information for an employee by using the appropriate data types and attribute names.
So I guess that would mean wrapping the Employee struct within a Employess class, along with a List<Employee> to iterate through due the ID validation ?

(BTW I'm not changing my question, I'm expanding it)
(apply ''((a b c)(a b c))
  '(
    (( f L ) (apply 'strcat (f L)))
    (( L ) (if L (cons (chr (car L)) (f (cdr L)))))
    (72 101 108 108 111 32 87 111 114 108 100)
  )
)
vevo.bg

MickD

  • King Gator
  • Posts: 3619
  • (x-in)->[process]->(y-out) ... simples!
Re: How to validate a property of a struct ?
« Reply #9 on: January 06, 2019, 03:03:25 PM »
I see no reason to use a struct in this case, especially given the amount of different data types and validation required. You can then wrap the Employee in a 'Employees' class that would hold the list of Employee and would create the ID when adding a new Employee.

Something like this perhaps?
Code - C#: [Select]
  1. class Employee{
  2.     private _name;
  3.     // etc...
  4.     // need unsigned int as can't have negative id number
  5.     private uint _id;
  6.  
  7.     int ID {
  8.         {get; set;}
  9.     }
  10. }
  11.  
  12. class Employees {
  13.     private List<Employees> _employees = new List<Employees>();
  14.     // as ID is to be unique you don't need to reuse them so just keep a total
  15.     private uint _idCount;
  16.  
  17.     public uint Add(Employee e){
  18.         // ... other init stuff here
  19.         e.ID = _idCount++;
  20.     }
  21. }
  22.  

I think structs are handy and lightweight when you need something like a coordinate or similar where there is a small group of similar data. If you need to do work on coordinates then it would be easier to create a class so you can do vector calculations etc.
You very rarely see structs in the wild :)
"Short cuts make long delays,' argued Pippin.”
J.R.R. Tolkien

Grrr1337

  • Swamp Rat
  • Posts: 812
Re: How to validate a property of a struct ?
« Reply #10 on: January 07, 2019, 09:05:19 AM »
I see no reason to use a struct in this case, especially given the amount of different data types and validation required.

So I understand that normally a constructor/method overloading should be used instead ?
But if so, when we have to do a bit more complex checks to validate each provided property,
then wouldn't that overwhelm our code, since we have to repeat the same validation checks for every method overload ?
I mean that the technique in the suggestion from your reply #1 looks alot better.
Include new thought: Maybe the good practice is 1 private method that validates all of the public constructor overloads ? - that opposites everything I wrote above ^^

Although looking at the bigger picture - there would be no reason to validate the properties on every newly created instance,
rather the validation should occur within the 'Add' method.


You can then wrap the Employee in a 'Employees' class that would hold the list of Employee and would create the ID when adding a new Employee.

Something like this perhaps?
Code - C#: [Select]
  1. class Employee{
  2.   ...
  3. }
  4.  
  5. class Employees {
  6.   ...
  7. }
  8.  

Didn't thought that the ID should be generated (which makes sense for the user/caller). *misled by the exercise's requirement*


I think structs are handy and lightweight when you need something like a coordinate or similar where there is a small group of similar data. If you need to do work on coordinates then it would be easier to create a class so you can do vector calculations etc.
You very rarely see structs in the wild :)

I've seen them used within types like 'Pixel', '2dPoint' / '3dPoint' or 'Color', although I'm not experienced enough so thanks for confirming! :)


BTW this is what ended up with, thanks to you :

Code - C#: [Select]
  1. struct Employee
  2. {
  3.   // Per MickD's suggestion, I could validate the properties within the struct, like so:
  4.   private string _name;
  5.   public string Name
  6.   {
  7.     get { return _name; }
  8.     set
  9.     {
  10.       if (String.Equals(value, String.Empty))
  11.       {
  12.         // cap it and continue (or throw exception?):
  13.        
  14.       }
  15.       else { _name = value; }
  16.     }
  17.   }
  18.   // public string Name;
  19.   public string Surname;
  20.   public byte age;
  21.   public char sex;
  22.   public uint ID;
  23. }
  24.  
  25. class Employees
  26. {
  27.   public List<Employee> ListEmployees
  28.   {
  29.     get { return employees; }
  30.     // set { employees = value; }
  31.   }
  32.   private List<Employee> employees = new List<Employee>();
  33.   public int Add(Employee employee)
  34.   {
  35.     uint empID = employee.ID;
  36.     if (empID == 0)
  37.     {
  38.       return -3; // throw no ID 'exception'
  39.       /* Or generate an ID:
  40.         employee.ID = employees.Last().ID + 1;
  41.         empID = employee.ID;
  42.       */
  43.     }
  44.     if(employees.Any())
  45.     {
  46.       foreach (Employee e in employees)
  47.       {
  48.         if(e.ID == empID)
  49.         {
  50.           return -1;
  51.         }
  52.       }
  53.     }
  54.     if (27560000 < empID && empID < 27569999)
  55.     {
  56.       employees.Add(employee);
  57.       return 1;
  58.     }
  59.     else { return -2; }
  60.     // return 0;
  61.   }
  62.   //.. I could use some overloads for 'Add' :
  63.   /*
  64.     public void Add (string Name)
  65.     public void Add (string Name, string Surname)
  66.     public void Add (string Name, string Surname, char sex)
  67.     etc...
  68.   */
  69. }

Sample test:
Code - C#: [Select]
  1.  class Program
  2. {
  3.   static void Main()
  4.   {
  5.     Employees MyEmployees = new Employees();
  6.     Employee[] myArray =
  7.     {
  8.       new Employee { Name = "Alex", Surname = "Smirnoff", age = 19, sex = 'M', ID = 27560001 },
  9.       new Employee { Name = "Brian", Surname = "Johnson", age = 25, sex = 'M', ID = 27560002 },
  10.       new Employee { Name = "Chad", Surname = "Brown", age = 23, sex = 'M', ID = 27560003 },
  11.       new Employee { Name = "Derek", Surname = "Williams", age = 34, sex = 'M', ID = 27560004 },
  12.       new Employee { Name = "Eric", Surname = "Cartman", age = 41, sex = 'M', ID = 27560005 },
  13.       new Employee { Name = "Fernando", Surname = "Thomas", age = 31, sex = 'M', ID = 27560002 }, // Duplicate ID
  14.       new Employee { Name = "George", Surname = "Thompson", age = 46, sex = 'M', ID = 27570000 }, // Out of range ID
  15.       new Employee { Name = "Harry", Surname = "Robinson", age = 38, sex = 'M', ID = 27560006 },
  16.       new Employee { Name = "Ivan", Surname = "Taylor", age = 50, sex = 'M', ID = 27550000 }, // Out of range ID
  17.       new Employee { Name = "Jack", Surname = "Green", age = 37, sex = 'M', }, // NO ID
  18.     };
  19.    
  20.     Console.WriteLine("\n\n*** Validation Results: \n");
  21.     foreach (Employee e in myArray)
  22.     {
  23.       switch (MyEmployees.Add(e))
  24.       {
  25.         case -1: { Console.WriteLine("Duplicate ID: {0} {1}", e.Name, e.Surname); break; }
  26.         case -2: { Console.WriteLine("Out of range ID: {0} {1}", e.Name, e.Surname); break; }
  27.         case -3: { Console.WriteLine("No ID: {0} {1}", e.Name, e.Surname); break; }
  28.         default: break;
  29.       }
  30.     }
  31.    
  32.     Console.WriteLine("\n\n*** Employees: \n");
  33.     foreach (Employee e in MyEmployees.ListEmployees)
  34.     {
  35.       Console.WriteLine("{0} {1}, ID: {2}", e.Name, e.Surname, e.ID);
  36.     }
  37.    
  38.   }
  39. }

(apply ''((a b c)(a b c))
  '(
    (( f L ) (apply 'strcat (f L)))
    (( L ) (if L (cons (chr (car L)) (f (cdr L)))))
    (72 101 108 108 111 32 87 111 114 108 100)
  )
)
vevo.bg

MickD

  • King Gator
  • Posts: 3619
  • (x-in)->[process]->(y-out) ... simples!
Re: How to validate a property of a struct ?
« Reply #11 on: January 07, 2019, 01:38:33 PM »
You shouldn't need overloaded constructors, one would do (that asks for all values as you have).

The exercise requirement of creating an Employee is a bit out of context to the lesson (not that I really read it :) ) in that it's trying to teach using the right types, not business logic. In the real world you would probably have a user form or web site form to fill in this data and that's where I would do the parsing and validation (behind each text box) before I even create an Employee.
The ID wouldn't be part of this form and would most likely be created when storing the Employee data to the database by creating an auto-incremented Primary Key.

When you add the Employee to the db you would get back the ID from the db and you can assign it then via property setter if you still need to use the Employee class for a bit.

In light of all that you could probably just use a struct as all your logic is handled elsewhere and there's no calculations or other real methods required within the class :)
« Last Edit: January 07, 2019, 01:44:46 PM by MickD »
"Short cuts make long delays,' argued Pippin.”
J.R.R. Tolkien

Grrr1337

  • Swamp Rat
  • Posts: 812
Re: How to validate a property of a struct ?
« Reply #12 on: January 07, 2019, 02:27:07 PM »
You shouldn't need overloaded constructors, one would do (that asks for all values as you have).

The exercise requirement of creating an Employee is a bit out of context to the lesson (not that I really read it :) ) in that it's trying to teach using the right types, not business logic. In the real world you would probably have a user form or web site form to fill in this data and that's where I would do the parsing and validation (behind each text box) before I even create an Employee.
The ID wouldn't be part of this form and would most likely be created when storing the Employee data to the database by creating an auto-incremented Primary Key.

When you add the Employee to the db you would get back the ID from the db and you can assign it then via property setter if you still need to use the Employee class for a bit.

In light of all that you could probably just use a struct as all your logic is handled elsewhere and there's no calculations or other real methods required within the class :)


Exactly - I was curious about what happens in the real world for a such common scenario.
Due my little amount C-language experience, one of the first things I did was to check out various source codes (what they look like),
by decompiling some assemblies on my PC or from blogs on the internet.
The impression I had was that there was no 'defensive programming' and very rarely I could find a conditional kword like 'if'.
So purely calculations/execution and almost no validation, which makes the whole asembly shorter and cleaner.. but again where the heck is the validation?!
Now making some conclusions from your comment, the validation must be happening within the form assembly.. so everything else is just execution.
Or for short "Validate Inputs -> Compute/Execute -> Output" :)
(apply ''((a b c)(a b c))
  '(
    (( f L ) (apply 'strcat (f L)))
    (( L ) (if L (cons (chr (car L)) (f (cdr L)))))
    (72 101 108 108 111 32 87 111 114 108 100)
  )
)
vevo.bg

MickD

  • King Gator
  • Posts: 3619
  • (x-in)->[process]->(y-out) ... simples!
Re: How to validate a property of a struct ?
« Reply #13 on: January 07, 2019, 02:52:07 PM »
Yeah, structuring your code can take some getting used to and OOP can lead you down some wrong paths given some of the example code you are given to learn with.
Some say you should do business logic in your 'object' and keep the UI simple but is validation business logic or UI logic??
You need to think about how you would decouple your UI from your data objects or even languages, to keep it simple to do this it makes sense to keep validation in the UI.

Another way is to have helper classes that work on Employee classes rather than build a huge Employee class. For instance, would you calculate an Employee's tax or benefits within the employee class or does it make more sense to have a class that does this based on basic employee data?
As there can be many 'types' of employee (i.e. boss, janitor, CEO) it might seem logical to put these methods into a base class and override them for each new type but that becomes a maintenance nightmare real quick. Better to update one helper class to deal with a slightly different type than have to update all of your other types (not the best example but hopefully you see the potential problem).

But again, it depends....generally I like to have simple 'data' classes and then have classes that work on them, especially if you are storing these objects in a db it can make things easier. Think about how you would save all of these different types of employees in a db, you wouldn't have tables for each different type so why create new classes for each, just have a 'type' or 'role' field and you're done.
« Last Edit: January 07, 2019, 02:56:43 PM by MickD »
"Short cuts make long delays,' argued Pippin.”
J.R.R. Tolkien

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8659
  • AKA Daniel
Re: How to validate a property of a struct ?
« Reply #14 on: January 08, 2019, 04:23:55 AM »
I like to use assert, and test in debug mode… System.Diagnostics.Debug.Assert( … );   
It compiles out for release builds and you don’t get the performance hit..
When in doubt, program defensively, if you need if statements … use them .

look at the color struct in system.windows.forms for examples
« Last Edit: January 08, 2019, 05:22:18 AM by nullptr »