Assigning an int literal to a byte variable is legal:
byte b = 123; // legal
However, assigning an int variable to a byte variable is illegal:
int i = 123;
byte b = i; // illegal
Assigning an int literal to a byte variable is legal:
byte b = 123; // legal
However, assigning an int variable to a byte variable is illegal:
int i = 123;
byte b = i; // illegal
Because when you assign a literal(constant value) compiler can prove the value fits in byte. When you assign a variable it can't.
If you assign a constant compiler is more than happy to compile because it can confirm that value is within the range of (0 - 255) which is the valid range for byte.
For example the following code compiles without any problem.
const int i = 123;
byte b = i;
The accepted answer is not quite correct.
In the second example, of course the compiler could prove that the value will fit, using simple static analysis. It's not allowed to, by the language specification.
It's trivial for a compiler such as the IL Jitter to prove this, and it does on many occasions. The C# compiler cannot accept this because it is against the specification.
The example given in that answer, is allowed because the spec allows it, not just because there is proof.
const int i = 123;
byte b = i;
Let's take a look at the spec, ECMA-334 section §11.2.10 (you may find microsoft.com easier to navigate)
11.2.10 Implicit constant expression conversions
An implicit constant expression conversion permits the following conversions:
- A constant-expression(§12.20) of type
intcan be converted to typesbyte,byte,short,ushort,uint, orulong, provided the value of the constant-expression is within the range of the destination type.
Let's take a look at §12.20 at what a constant-expression is defined as:
Constant expressions
A constant_expression is an expression that can be fully evaluated at compile-time.
A constant expression must be the
nullliteral or a value with one of the following types:sbyte,byte,short,ushort,int,uint,long,ulong,char,float,double,decimal,bool,object,string, or any enumeration type. Only the following constructs are permitted in constant expressions:
- Literals (including the
nullliteral).- References to
constmembers of class and struct types.- References to members of enumeration types.
- References to
constparameters or local variables- Parenthesized sub-expressions, which are themselves constant expressions.
- Cast expressions, provided the target type is one of the types listed above.
checkedanduncheckedexpressions- Default value expressions
- Nameof expressions
- The predefined
+,-,!, and~unary operators.- The predefined
+,-,*,/,%,<<,>>,&,|,^,&&,||,==,!=,<,>,<=, and>=binary operators, provided each operand is of a type listed above.- The
?:conditional operator.
So, going back to the first example in the quesiton
byte b = 123;
The value 123 is a literal integer, which is a constant expression, and fits a byte therefore it can be implicitly converted into byte.
Next,
int i = 123;
byte b = i;
Here the value i is not a constant expression, therefore it cannot be implicitly converted to byte. There is no way for the compiler to allow this, because the spec disallows it.
Finally the example in the other answer
const int i = 123;
byte b = i;
Here, i is a constant expression (because it is a reference to a const), whose value is known to fit into a byte, hence it is allowed by the spec.