The way to go depends on what is really stored in Values["id"]. If it is in fact an int, you can test for int with Values["id"] is int. The Values[] property is typed as object. Therefore it can be null. But this does NOT mean, that the stored int is a Nullable<int>. (see my update below.)
If you assign an int (and all other non-reference types) to an object variable or property, it will be boxed. I.e. it will be packed into an object of the corresponding type. int or System.Int32 exists as value type as well as a boxed and immutable System.Int32 reference type. Because of its immutability, you don't notice that it is a reference type. An int can be boxed with object obj = 5; and unboxed with int i = (int)obj;.
On the other hand, if the id was stored as string then you would have to convert it to a number
int id;
if (Int32.TryParse((string)Page.RouteData.Values["id"], out id)) {
// use id here
}
UPDATE:
There seems to be some confusion with null and Nullable<T>.
int? i; // Same as Nullable<int> or Nullable<System.Int32> or System.Int32?
object obj;
bool test;
i = null;
test = i.HasValue; // ==> false
test = i == null; // ==> true
// Now comes the strange part
obj = 5; // The int is boxed here.
// Debugger shows type of obj as "object {int}"
test = obj is int; // ==> true
test = obj is int?; // ==> true
int x = (int)obj; // ==> 5, the int is unboxed here.
// But
obj = null;
// Debugger shows type of obj as "object"
test = obj is int; // ==> false
test = obj is int?; // ==> false
test = obj == null; // ==> true
// And
i = 5;
obj = i; // i is a Nullable<int>
// Debugger shows type of obj as "object {int}"
test = obj is int; // ==> true
test = obj is int?; // ==> true
test = obj == null; // ==> false
i = null;
obj = i;
// Debugger shows type of obj as "object"
test = obj is int; // ==> false
test = obj is int?; // ==> false
test = obj == null; // ==> true
Both obj is int and obj is int? return true if obj contains an int number but both return false if obj contains null! A null Nullable<int> is converted to (object)null when asssigned to obj and is no more Nullable<int>.
The debugger shows the type of obj as object {int} when there is a number stored, no matter whether an int or an int? was assigned! The type of obj is object when null is stored.
So Chuong Le is in fact right!