The confusion here is because unlike pointers (as in * ), "ref" in C# is not a part of a type, but a part of a method signature. It applies to the parameter and means "this must not be copied". It does not mean "this argument has reference type".
Parameter passed by ref, instead of representing a new storage location, is instead an alias to some existing location. How alias is created is technically an implementation detail. Most often aliases are implemented as managed references, but not always. In some async related cases, for example, a reference to an array element could be internally represented as a combination of array and index.
Essentially for all purposes your a and b are still understood by C# as int-typed variables. It is legal and completely normal to use them in any expression that takes int values like a+b, or SomeMethod(a,b) and in those cases the actual int values stored in a and b are used.
There is really no concept of a "reference" as an entity that you can directly work with in C#.
Unlike pointers, the actual values of managed references must be assumed to be able to change at any moment, or even asynchronously, by GC, so the set of meaningful scenarios on managed references would be extremely limited.
ref
modifier does not cause the corresponding argument to be boxed to a reference type. – Intendancy