Expressions in C# and F#
The managed expression evaluator accepts most expressions written in C#.
The managed expression evaluator does not recognize F# expressions, however. If you are debugging F#, you need to translate your expressions into C# syntax before entering the expressions into a debugger window or dialog box. When you translate expressions from F# to C#, be sure to remember that C# uses the == operator to test for equality, while F# uses the single =.
The following sections offer specific information and discuss some of the expression types that are not supported or partially supported:
The expression evaluator ignores public, protected, internal, and private access modifiers. You can call a private method from the Watch window, for example. Because the expression evaluator ignores access modifiers, it is possible for an unexpected load to be invoked.
The expression evaluator performs all evaluations in an implicit unsafe context, whether the code being executed is safe or unsafe.
The expression evaluator also ignores checked blocks and the /checked compiler option. All expressions are evaluated in an unchecked context.
You can customize the display of custom data types using attributes. For more information, see Displaying Custom Data Types.
Simple cast expressions work in the debugger:
Casts that involve pointers do not work in the debugger.
The expression evaluator can evaluate variables that are statically typed as dynamic. It can also evaluate objects that implement the IDynamicObject interface. When objects that implement the IDynamicObject interface are evaluated in the Watch window, a Dynamic View node is added. The Dynamic View node shows object members but does not allow editing the values of the members.
The following features of dynamic objects are not supported:
The compound operators +=, -=, %=, /=, and *=
Many casts, including numeric casts and type-argument casts
Method calls with more than two arguments
Property getters with more than two arguments
Property setters with arguments
Assigning to an indexer
Boolean operators && and ||
Debugger expressions can use any identifier visible within the current scope. If the debugger is stopped in method Magh, for example, you can use any identifier visible within Magh, including constants, variable names, and method names.
The debugger can correctly display any variable of a primitive, enum, or intrinsic type. For variables of class type, the debugger correctly displays the value based on the derived-most type. If you have an object leo of type Lion, derived from type Cat, you can evaluate leo.Claws and get the correct value for an object of type Lion.
You can assign a new value to any left-hand expression that is an l-value. This includes primitive, class, and System.Object types.
The debugger supports the evaluation of methods, including overloaded methods. Therefore, you can enter either of the following expressions, and the debugger will call the correct version of the overloaded methods:
Evaluating a method in the debugger actually calls and executes the code for that method. If the method has side effects, evaluating the method in a debugger window will change the state of your program, which can produce unexpected results.
When you set a breakpoint on an overloaded method, the location of the breakpoint depends on how you specify the method. If you specify the complete signature (method name and full argument list), the debugger sets one breakpoint on the specified overload. If you specify only the method name, the debugger's behavior depends on a Visual Studio options setting. If the Use IntelliSense to verify the function name check box is not selected, the debugger will set one breakpoint on each overload of that method name. Otherwise the Choose Breakpoint dialog box will open, allowing you to specify which overload(s) to put the breakpoint on. For more information, see Using Breakpoints.
Creation of new anonymous methods is not supported in the debugger in this version of Visual Studio.
The debugger correctly evaluates most built-in operators, including:
Relational and equality operators: ( expr1> expr2, expr1< expr2, expr1<= expr2, expr1=> expr2, expr1== expr2, expr1!= expr2).
Boolean operators: (expr1&& expr2, expr1|| expr2, expr1? expr2: expr3).
Arithmetical operators: (expr1+ expr2,expr1- expr2, expr1* expr2, expr1/ expr2, expr1% expr2 ).
Logical operators: (expr1& expr2, expr1^ expr2, expr1| expr2 ).
Shift operators: (expr1>> expr2, expr1<< expr2 ).
Assignment operators: ( lvalue= expr2,lvalue*= expr2,lvalue/= expr2, lvalue%= expr2, lvalue+= expr2, lvalue-= expr2, lvalue<<= expr2, lvalue>>= expr2, lvalue&= expr2, lvalue^= expr2, lvalue|= expr2).
Unary operators: ( +expr1, - expr1, expr1++, ++expr1, expr1--, --expr1).
Most overloaded operators work in the debugger.
Overloaded infix operators +, -, /, %, and & work:
Overloaded infix operators =, &&, &, and ||, do not work:
Overloaded infix operators << and >> do not work if both operands are class variables:
Overloaded prefix operators +, -, ++, --, !, and ~ work:
Overloaded suffix operators ++ and -- work:
Overloaded indexers work:
The debugger can evaluate properties in any variable window. However, evaluating a property in the debugger can have side effects that produce unexpected and unwanted results. To protect against side effects caused by accidental evaluation, you can turn property evaluation off in the Options dialog box.
The debugger recognizes the indexed operator when it is used with strings as well as arrays. So, for example, you can enter:
The Watch window will display the correct value:
In C#, unlike native C/C++, you can edit the value of a string in the debugger. In addition, you can use the Length operator on a string:
In C#, you can concatenate strings:
"hello" + "world"
The debugger supports the typeof and sizeof operator by transforming it into the equivalent .NET Framework function.
typeof ( expression)
is transformed into:
The debugger then evaluates this transformed expression.
The debugger supports the sizeof operator.
You cannot call WebMethods from debugger windows.