Search code examples
c#classobjectlinq-to-objects

How do i check string to see if all characters are integers, that it is 8 characters in length and throw an argument for each?


Class student and the main are just for reference.. In the try catch block there are two separate s1.SNum = "string" that should each throw a separate argument but both throw the same one every time and I'm not figuring it out.

class Student
    {
       public string FirstName { get; private set; }
       public string LastName { get; private set; }
       public Date BirthDate { get; private set; }

       public Date catalog;
       public string sNum;
     }

This is the code im having trouble with. I want to have two sets that throw exceptions for sNum. One for not having all digits and one for not having a length of eight.

public string SNum
        {
            get
            {
                return sNum;
            }

            set
            {
            foreach (char c in sNum)
            {
                int count = 0;
                char charToCount = ',';
                bool result = (SNum.All(Char.IsDigit));

                if (result == false)
                {
                    throw new ArgumentOutOfRangeException(nameof(SNum), value,
                    $"{nameof(SNum)} characters are not all integers.");
                }

                if (c == charToCount)
                {
                    count++;
                }
                else if (count != 8)       BOTH WILL THROW THIS ARGUMENT RIGHT NOW
                {
                    throw new ArgumentOutOfRangeException(nameof(SNum), value,
                    $"{nameof(SNum)} length is not eight.");
                }
            }
        }

And the Main Class for reference to the try catch..Even if I'm checking for any letters s1.SNum = "158945K9"; will still throw the same exception as s1.SNum = "1234567";

            // attempt to assign invalud sNum length
            try
            {
                s1.SNum = "1234567";  
            }
            catch (ArgumentOutOfRangeException ex)
            {
                Console.WriteLine($"{ex.Message}\n");
            }

            // attempt to assign invalud sNum character
            try
            {
                s1.SNum = "158945K9";
            }
            catch (ArgumentOutOfRangeException ex)
            {
                Console.WriteLine($"{ex.Message}\n");
            }

Solution

  • If all you care about is that the value is all digits and is 8 characters long then the implementation is far simpler than you have:

    set
    {
        if (value.Any(ch => !char.IsDigit(ch))
            throw new ArgumentException("All characters must be digits.");
    
        if (value.Length != 8)
            throw new ArgumentException("Value must be eight characters in length.");
    
        sNum = value;
    }
    

    It seems like there's more to it than that though, but you haven't explained the rest. If you want to allow commas and they don't get included in the length calculation then that changes to something like this:

    set
    {
        if (value.Any(ch => ch != ',' && !char.IsDigit(ch))
            throw new ArgumentException("All characters must be digits or commas.");
    
        if (value.Count(ch => ch != ',') != 8)
            throw new ArgumentException("Value must contain eight digits.");
    
        sNum = value;
    }
    

    You might prefer to use All rather than Any, which will also work in both cases and avoids the double negation in the second code snippet, but still requires the exact same number of characters in each case:

    set
    {
        if (!value.All(ch => char.IsDigit(ch))
            throw new ArgumentException("All characters must be digits.");
    
        if (value.Length != 8)
            throw new ArgumentException("Value must be eight characters in length.");
    
        sNum = value;
    }
    

    and:

    set
    {
        if (!value.All(ch => ch == ',' && char.IsDigit(ch))
            throw new ArgumentException("All characters must be digits or commas.");
    
        if (value.Count(ch => ch != ',') != 8)
            throw new ArgumentException("Value must contain eight digits.");
    
        sNum = value;
    }
    

    Using Any also maintains more consistency with the other if statements, but that's a very minor thing.

    Note also that I have thrown an ArgumentException rather than an ArgumentOutOfRangeException. There's no specific range of valid values in this case so you should not be throwing an exception that indicates that there is. If there was a range then you could describe it using a minimum and maximum value.