Common Expression Evaluator Features
This topic describes various Expression Evaluator features that are common to the debugger, varying only by language.
Implicit Variables
In Visual Basic and C#, you can create implicit variables by using the expression evaluator. These implicit variables never go out of scope and can be treated as any other variable.
In C#, you can create an implicit variable by declaring it in the expression evaluator. For example, you can enter the following C# code in the Immediate window:
int b = 100;
When you execute this code in the Immediate window, the new implicit variable appears in the Locals window with the $ sign in front of the variable name, in this case, $b.
In Visual Basic, you cannot declare implicit variables in the expression evaluator. However, if you use an undeclared variable in the Visual Basic expression evaluator, an implicit variable is created automatically. In Visual Basic, implicit variables are not listed in the Locals window.
Breakpoints
If you use the Immediate window to evaluate either a Visual Basic or C# method or function that contains a breakpoint, that breakpoint is hit and a new frame appears on the Call Stack. Here is a C# example:
class Program
{
static void Main(string[] args)
{
// Breakpoint here:
int a = 20;
}
}
If you set a breakpoint where the comment indicates, compile and execute the program by pressing F5, you will hit the breakpoint in a regular manner. If you now evaluate the method Main by typing Program.Main(null) into the Immediate window, the breakpoint will be hit a second time, and there will be an entry for the method on the Call Stack.
Evaluating in the Watch Window
To avoid possible unwanted side effects, a function or method call is not automatically evaluated every time that the debugger steps. Instead, an icon enables you to manually update the result. It appears in the Value column. This enables you to evaluate the call manually. For more information, see Side Effects and Expressions.
Object Identity
This feature is not available for Visual Basic.
Some applications create many instances of a class. In these applications, it is frequently useful to have an identifier to distinguish a given instance of the class. This can be useful, for example, if a specific instance of the class is not behaving as expected or a specific instance has been inserted more than once into a collection that should only contain it once.
Native Object Identity
When you debug unmanaged code, you can uniquely identify an object by using its address. This is important for two reasons:
You can track an object just by using its address. This includes the ability to use an address to:
View the value of the object at that address.
Check for equality. Frequently, the address for an object can be used in the same way as the object variable itself.
You can use the address of an object, the instance, to set a breakpoint on a method in that specific instance.
For example, suppose you have an object that is an instance of class CMyType, with address 0xcccccccc. You can specify a function breakpoint on method aMethod of that instance as follows:
((CMyType *) 0xcccccccc)->aMethod
Managed Object Identity
With managed code, you cannot use the address of the object to identify it. Instead, you use an integer known as the object ID generated by the common language runtime (CLR) debugging services and associated with the object. This number is a positive integer generated by the CLR debugging services. The object ID value has no significance except to uniquely identify the object.
Object handles are displayed as variable-length, decimal integers, with the number sign (#) appended after the number, without any leading zeros, such as 5#. Handles appear in the Value column in different debugger data windows.
To create an object ID for a variable, right-click the variable, and select Make Object ID. The debugger will display a number with the pound (#) sign appended after it, such as 123#. To delete an object ID, right-click the variable, and select Delete Object ID.
When a breakpoint is hit, you can type a variable's handle into the Watch window. The debugger displays the value of the object ID, and you can expand and inspect it just like any other variable.
You can use the object ID to set a breakpoint on a method of a specific instance. For example, suppose you have an object that is an instance of class CMyType, and the instance has object ID 5#. Class CMyType includes a method aMethod. You can set a function breakpoint on method aMethod of instance 5# as follows:
((CMyType) 5#).aMethod
You can also use the object ID in a breakpoint condition. The following example shows how you can test the object ID in a condition.
this == 5#