IdNumber: a string of fixed length and with character constraints In my program, I have special id numbers. They have a fixed length of 10 characters and may only contain digits and lowercase letter. I created my own data type for this. I want to be able to assign string values to it (with the implicit operator). When I do so, there should be automatically a verification if all conditions are met (the length and the constraints at the characters).

public class IdNumber
{
    private string idnumber;

    public static implicit operator IdNumber(string value)
    {
        if (value.Length == 10 &amp;&amp; value.All(c =&gt; IsDigit(c) || IsLowercaseLetter(c)))
        {
            IdNumber m = new IdNumber();
            m.idnumber = value;
            return m;
        }
        else
        {
            throw new ArgumentException("id numer must have length 10 and must only have digits and lower case-letters");
        }
    }

    public override string ToString()
    {
        return idnumber;
    }

    public override int GetHashCode()
    {
        return idnumber.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        if(obj is IdNumber other)
        {
            return this.idnumber == other.idnumber;
        }
        else
        {
            return false;
        }
    }

    public static bool operator ==(IdNumber m1, IdNumber m2)
    {
        if(m1 is null)
        {
            return m2 is null;
        }
        return m1.Equals(m2);
    }

    public static bool operator !=(IdNumber m1, IdNumber m2)
    {
        return !(m1 == m2);
    }

    private static bool IsDigit(char c)
    {
        return c &gt;= '0' &amp;&amp; c &lt;= '9';
    }

    private static bool IsLowercaseLetter(char c)
    {
        return c &gt;= 'a' &amp;&amp; c &lt;= 'z';
    }
}


Now I can use it via

IdNumber myId = "ab45jk23zz";
IdNumber otherId = "asfd" // throws exception


I have never used the implicit operator and I am also not sure about overriding the GetHashCode method (I want to use them as a key in a Dictionary, so it is important this works correctly). Hence I want to be sure I did not overlook anything. Of course, any other suggestions for improvement are welcome.
I will review your code from top to bottom.  

private string idnumber;  


this should be named using camelCase casing and because you don't change its value you should make it readonly which means you can only assign a value to it inside the constructor or by initialising like e.g private string idnumber = "somevalue";. Because you set this value only inside the implicit operator you should add a private constructor which has a string as argument. This would then look like this  

public class IdNumber
{
    private readonly string idNumber;
    private IdNumber(string idNumber)
    {
        this.idNumber = idNumber;
    }


Because the implicit operator is public you should validate the argument value wether it is null. It just looks better to throw an ArgumentNullException than to receive an NullReferenceException. 

Instead of using value.All(c =&gt; IsDigit(c) || IsLowercaseLetter(c)) you could use a simple Regex to do the validation for you. This will shorten your code because the two methods IsDigit() and IsLowercaseLetter() won't be needed anymore.  

The implicit operator would then look like this  

public static implicit operator IdNumber(string value)
{
    if (value is null) { throw new ArgumentNullException(nameof(value)); }

    if (Regex.IsMatch(value, "[0-9a-z]{10}"))
    {
        return new IdNumber(value);
    }
    throw new ArgumentException("id numer must have length 10 and must only have digits and lower case-letters");
}


ToString() and GetHashCode() are both fine but in the Equals() method you can either just remove the else like so  

public override bool Equals(object obj)
{
    if(obj is IdNumber other)
    {
        return this.idNumber == other.idNumber;
    }

    return false;
}  


or combine the if condition with the idNumber comparision like so  

public override bool Equals(object obj)
{
    return (obj is IdNumber other) 
        &amp;&amp; this.idNumber == other.idNumber;
}