Standard primitive types vs custom structs in public API
custom value type

I would use this becasue the disadvantage that you name 


  you need always cast values of primitive types to FourBitNumber which is inconvenient especially with literals.


can be easily overcome by implementing an implict operator for FourBitNumber to byte:

public static implicit operator byte(FourBitNumber value) =&gt; value._someValue;


and an explicit one for byte to FourBitNumber

public static explicit operator FourBitNumber(byte value) =&gt; new FourBitNumber(value);


so now it doesn't have any disadvanteges ;-)