- •Foreword
- •Introduction
- •Scope
- •Conformance
- •Normative references
- •Definitions
- •Notational conventions
- •Acronyms and abbreviations
- •General description
- •Language overview
- •Getting started
- •Types
- •Predefined types
- •Conversions
- •Array types
- •Type system unification
- •Variables and parameters
- •Automatic memory management
- •Expressions
- •Statements
- •Classes
- •Constants
- •Fields
- •Methods
- •Properties
- •Events
- •Operators
- •Indexers
- •Instance constructors
- •Destructors
- •Static constructors
- •Inheritance
- •Static classes
- •Partial type declarations
- •Structs
- •Interfaces
- •Delegates
- •Enums
- •Namespaces and assemblies
- •Versioning
- •Extern Aliases
- •Attributes
- •Generics
- •Why generics?
- •Creating and consuming generics
- •Multiple type parameters
- •Constraints
- •Generic methods
- •Anonymous methods
- •Iterators
- •Lexical structure
- •Programs
- •Grammars
- •Lexical grammar
- •Syntactic grammar
- •Grammar ambiguities
- •Lexical analysis
- •Line terminators
- •Comments
- •White space
- •Tokens
- •Unicode escape sequences
- •Identifiers
- •Keywords
- •Literals
- •Boolean literals
- •Integer literals
- •Real literals
- •Character literals
- •String literals
- •The null literal
- •Operators and punctuators
- •Pre-processing directives
- •Conditional compilation symbols
- •Pre-processing expressions
- •Declaration directives
- •Conditional compilation directives
- •Diagnostic directives
- •Region control
- •Line directives
- •Pragma directives
- •Basic concepts
- •Application startup
- •Application termination
- •Declarations
- •Members
- •Namespace members
- •Struct members
- •Enumeration members
- •Class members
- •Interface members
- •Array members
- •Delegate members
- •Member access
- •Declared accessibility
- •Accessibility domains
- •Protected access for instance members
- •Accessibility constraints
- •Signatures and overloading
- •Scopes
- •Name hiding
- •Hiding through nesting
- •Hiding through inheritance
- •Namespace and type names
- •Unqualified name
- •Fully qualified names
- •Automatic memory management
- •Execution order
- •Types
- •Value types
- •The System.ValueType type
- •Default constructors
- •Struct types
- •Simple types
- •Integral types
- •Floating point types
- •The decimal type
- •The bool type
- •Enumeration types
- •Reference types
- •Class types
- •The object type
- •The string type
- •Interface types
- •Array types
- •Delegate types
- •Boxing and unboxing
- •Boxing conversions
- •Unboxing conversions
- •Variables
- •Variable categories
- •Static variables
- •Instance variables
- •Instance variables in classes
- •Instance variables in structs
- •Array elements
- •Value parameters
- •Reference parameters
- •Output parameters
- •Local variables
- •Default values
- •Definite assignment
- •Initially assigned variables
- •Initially unassigned variables
- •Precise rules for determining definite assignment
- •General rules for statements
- •Block statements, checked, and unchecked statements
- •Expression statements
- •Declaration statements
- •If statements
- •Switch statements
- •While statements
- •Do statements
- •For statements
- •Break, continue, and goto statements
- •Throw statements
- •Return statements
- •Try-catch statements
- •Try-finally statements
- •Try-catch-finally statements
- •Foreach statements
- •Using statements
- •Lock statements
- •General rules for simple expressions
- •General rules for expressions with embedded expressions
- •Invocation expressions and object creation expressions
- •Simple assignment expressions
- •&& expressions
- •|| expressions
- •! expressions
- •?: expressions
- •Anonymous method expressions
- •Yield statements
- •Variable references
- •Atomicity of variable references
- •Conversions
- •Implicit conversions
- •Identity conversion
- •Implicit numeric conversions
- •Implicit enumeration conversions
- •Implicit reference conversions
- •Boxing conversions
- •Implicit type parameter conversions
- •Implicit constant expression conversions
- •User-defined implicit conversions
- •Explicit conversions
- •Explicit numeric conversions
- •Explicit enumeration conversions
- •Explicit reference conversions
- •Unboxing conversions
- •User-defined explicit conversions
- •Standard conversions
- •Standard implicit conversions
- •Standard explicit conversions
- •User-defined conversions
- •Permitted user-defined conversions
- •Evaluation of user-defined conversions
- •User-defined implicit conversions
- •User-defined explicit conversions
- •Anonymous method conversions
- •Method group conversions
- •Expressions
- •Expression classifications
- •Values of expressions
- •Operators
- •Operator precedence and associativity
- •Operator overloading
- •Unary operator overload resolution
- •Binary operator overload resolution
- •Candidate user-defined operators
- •Numeric promotions
- •Unary numeric promotions
- •Binary numeric promotions
- •Member lookup
- •Base types
- •Function members
- •Argument lists
- •Overload resolution
- •Applicable function member
- •Better function member
- •Better conversion
- •Function member invocation
- •Invocations on boxed instances
- •Primary expressions
- •Literals
- •Simple names
- •Invariant meaning in blocks
- •Parenthesized expressions
- •Member access
- •Identical simple names and type names
- •Invocation expressions
- •Method invocations
- •Delegate invocations
- •Element access
- •Array access
- •Indexer access
- •This access
- •Base access
- •Postfix increment and decrement operators
- •The new operator
- •Object creation expressions
- •Array creation expressions
- •Delegate creation expressions
- •The typeof operator
- •The checked and unchecked operators
- •Default value expression
- •Anonymous methods
- •Anonymous method signatures
- •Anonymous method blocks
- •Outer variables
- •Captured outer variables
- •Instantiation of local variables
- •Anonymous method evaluation
- •Implementation example
- •Unary expressions
- •Unary plus operator
- •Unary minus operator
- •Logical negation operator
- •Bitwise complement operator
- •Prefix increment and decrement operators
- •Cast expressions
- •Arithmetic operators
- •Multiplication operator
- •Division operator
- •Remainder operator
- •Addition operator
- •Subtraction operator
- •Shift operators
- •Relational and type-testing operators
- •Integer comparison operators
- •Floating-point comparison operators
- •Decimal comparison operators
- •Boolean equality operators
- •Enumeration comparison operators
- •Reference type equality operators
- •String equality operators
- •Delegate equality operators
- •The is operator
- •The as operator
- •Logical operators
- •Integer logical operators
- •Enumeration logical operators
- •Boolean logical operators
- •Conditional logical operators
- •Boolean conditional logical operators
- •User-defined conditional logical operators
- •Conditional operator
- •Assignment operators
- •Simple assignment
- •Compound assignment
- •Event assignment
- •Expression
- •Constant expressions
- •Boolean expressions
- •Statements
- •End points and reachability
- •Blocks
- •Statement lists
- •The empty statement
- •Labeled statements
- •Declaration statements
- •Local variable declarations
- •Local constant declarations
- •Expression statements
- •Selection statements
- •The if statement
- •The switch statement
- •Iteration statements
- •The while statement
- •The do statement
- •The for statement
- •The foreach statement
- •Jump statements
- •The break statement
- •The continue statement
- •The goto statement
- •The return statement
- •The throw statement
- •The try statement
- •The checked and unchecked statements
- •The lock statement
- •The using statement
- •The yield statement
- •Namespaces
- •Compilation units
- •Namespace declarations
- •Extern alias directives
- •Using directives
- •Using alias directives
- •Using namespace directives
- •Namespace members
- •Type declarations
- •Qualified alias member
- •Classes
- •Class declarations
- •Class modifiers
- •Abstract classes
- •Sealed classes
- •Static classes
- •Class base specification
- •Base classes
- •Interface implementations
- •Class body
- •Partial declarations
- •Class members
- •Inheritance
- •The new modifier
- •Access modifiers
- •Constituent types
- •Static and instance members
- •Nested types
- •Fully qualified name
- •Declared accessibility
- •Hiding
- •this access
- •Reserved member names
- •Member names reserved for properties
- •Member names reserved for events
- •Member names reserved for indexers
- •Member names reserved for destructors
- •Constants
- •Fields
- •Static and instance fields
- •Readonly fields
- •Using static readonly fields for constants
- •Versioning of constants and static readonly fields
- •Volatile fields
- •Field initialization
- •Variable initializers
- •Static field initialization
- •Instance field initialization
- •Methods
- •Method parameters
- •Value parameters
- •Reference parameters
- •Output parameters
- •Parameter arrays
- •Static and instance methods
- •Virtual methods
- •Override methods
- •Sealed methods
- •Abstract methods
- •External methods
- •Method body
- •Method overloading
- •Properties
- •Static and instance properties
- •Accessors
- •Virtual, sealed, override, and abstract accessors
- •Events
- •Field-like events
- •Event accessors
- •Static and instance events
- •Virtual, sealed, override, and abstract accessors
- •Indexers
- •Indexer overloading
- •Operators
- •Unary operators
- •Binary operators
- •Conversion operators
- •Instance constructors
- •Constructor initializers
- •Instance variable initializers
- •Constructor execution
- •Default constructors
- •Private constructors
- •Optional instance constructor parameters
- •Static constructors
- •Destructors
- •Structs
- •Struct declarations
- •Struct modifiers
- •Struct interfaces
- •Struct body
- •Struct members
- •Class and struct differences
- •Value semantics
- •Inheritance
- •Assignment
- •Default values
- •Boxing and unboxing
- •Meaning of this
- •Field initializers
- •Constructors
- •Destructors
- •Static constructors
- •Struct examples
- •Database integer type
- •Database boolean type
- •Arrays
- •Array types
- •The System.Array type
- •Array creation
- •Array element access
- •Array members
- •Array covariance
- •Arrays and the generic IList interface
- •Array initializers
- •Interfaces
- •Interface declarations
- •Interface modifiers
- •Base interfaces
- •Interface body
- •Interface members
- •Interface methods
- •Interface properties
- •Interface events
- •Interface indexers
- •Interface member access
- •Fully qualified interface member names
- •Interface implementations
- •Explicit interface member implementations
- •Interface mapping
- •Interface implementation inheritance
- •Interface re-implementation
- •Abstract classes and interfaces
- •Enums
- •Enum declarations
- •Enum modifiers
- •Enum members
- •The System.Enum type
- •Enum values and operations
- •Delegates
- •Delegate declarations
- •Delegate instantiation
- •Delegate invocation
- •Exceptions
- •Causes of exceptions
- •The System.Exception class
- •How exceptions are handled
- •Common Exception Classes
- •Attributes
- •Attribute classes
- •Attribute usage
- •Positional and named parameters
- •Attribute parameter types
- •Attribute specification
- •Attribute instances
- •Compilation of an attribute
- •Run-time retrieval of an attribute instance
- •Reserved attributes
- •The AttributeUsage attribute
- •The Conditional attribute
- •Conditional Methods
- •Conditional Attribute Classes
- •The Obsolete attribute
- •Unsafe code
- •Unsafe contexts
- •Pointer types
- •Fixed and moveable variables
- •Pointer conversions
- •Pointers in expressions
- •Pointer indirection
- •Pointer member access
- •Pointer element access
- •The address-of operator
- •Pointer increment and decrement
- •Pointer arithmetic
- •Pointer comparison
- •The sizeof operator
- •The fixed statement
- •Stack allocation
- •Dynamic memory allocation
- •Generics
- •Generic class declarations
- •Type parameters
- •The instance type
- •Members of generic classes
- •Static fields in generic classes
- •Static constructors in generic classes
- •Accessing protected members
- •Overloading in generic classes
- •Parameter array methods and type parameters
- •Overriding and generic classes
- •Operators in generic classes
- •Nested types in generic classes
- •Generic struct declarations
- •Generic interface declarations
- •Uniqueness of implemented interfaces
- •Explicit interface member implementations
- •Generic delegate declarations
- •Constructed types
- •Type arguments
- •Open and closed types
- •Base classes and interfaces of a constructed type
- •Members of a constructed type
- •Accessibility of a constructed type
- •Conversions
- •Using alias directives
- •Generic methods
- •Generic method signatures
- •Virtual generic methods
- •Calling generic methods
- •Inference of type arguments
- •Using a generic method with a delegate
- •Constraints
- •Satisfying constraints
- •Member lookup on type parameters
- •Type parameters and boxing
- •Conversions involving type parameters
- •Iterators
- •Iterator blocks
- •Enumerator interfaces
- •Enumerable interfaces
- •Yield type
- •This access
- •Enumerator objects
- •The MoveNext method
- •The Current property
- •The Dispose method
- •Enumerable objects
- •The GetEnumerator method
- •Implementation example
- •Lexical grammar
- •Line terminators
- •White space
- •Comments
- •Unicode character escape sequences
- •Identifiers
- •Keywords
- •Literals
- •Operators and punctuators
- •Pre-processing directives
- •Syntactic grammar
- •Basic concepts
- •Types
- •Expressions
- •Statements
- •Classes
- •Structs
- •Arrays
- •Interfaces
- •Enums
- •Delegates
- •Attributes
- •Generics
- •Grammar extensions for unsafe code
- •Undefined behavior
- •Implementation-defined behavior
- •Unspecified behavior
- •Other Issues
- •Capitalization styles
- •Pascal casing
- •Camel casing
- •All uppercase
- •Capitalization summary
- •Word choice
- •Namespaces
- •Classes
- •Interfaces
- •Enums
- •Static fields
- •Parameters
- •Methods
- •Properties
- •Events
- •Case sensitivity
- •Avoiding type name confusion
- •Documentation Comments
- •Introduction
- •Recommended tags
- •<code>
- •<example>
- •<exception>
- •<list>
- •<para>
- •<param>
- •<paramref>
- •<permission>
- •<remarks>
- •<returns>
- •<seealso>
- •<summary>
- •<value>
- •Processing the documentation file
- •ID string format
- •ID string examples
- •An example
- •C# source code
- •Resulting XML
Chapter 9 Lexical structure
1The type of a null-literal is the null type.
29.4.5 Operators and punctuators
3There are several kinds of operators and punctuators. Operators are used in expressions to describe
4 operations involving one or more operands. [Example: The expression a + b uses the + operator to add the
5two operands a and b. end example] Punctuators are for grouping and separating.
6operator-or-punctuator:: one of
7 |
{ |
} |
[ |
] |
( |
) |
. |
, |
: |
; |
8 |
+ |
- |
* |
/ |
% |
& |
| |
^ |
! |
~ |
9 |
= |
< |
> |
? |
++ |
-- |
&& |
|| |
== |
-> |
10 |
!= |
<= |
>= |
+= |
-= |
*= |
/= |
%= |
&= |
|= |
11 |
^= |
<< |
<<= |
:: |
|
|
|
|
|
|
12 right-shift:
13> >
14right-shift-assignment:
15> >=
16right-shift is made up of the two tokens > and >. Similarly, right-shift-assignment is made up of the two
17tokens > and >=. Unlike other productions in the syntactic grammar, no characters of any kind (not even
18whitespace) are allowed between the two tokens in each of these productions. [Note: Prior to the addition of
19generics to C#, >> and >>= were both single tokens. However, the syntax for generics uses the < and >
20characters to delimit type parameters and type arguments. It is often desirable to use nested constructed
21types, such as List<Dictionary<string, int>>. Rather than requiring the programmer to separate the
22> and > by a space, the definition of the two operator-or-punctuators was changed. end note]
239.5 Pre-processing directives
24The pre-processing directives provide the ability to conditionally skip sections of source files, to report error
25and warning conditions, and to delineate distinct regions of source code. [Note: The term “pre-processing
26directives” is used only for consistency with the C and C++ programming languages. In C#, there is no
27separate pre-processing step; pre-processing directives are processed as part of the lexical analysis phase.
28end note]
29pp-directive::
30
31
32
33
34
35
pp-declaration pp-conditional pp-line pp-diagnostic pp-region pp-pragma
36The following pre-processing directives are available:
37• #define and #undef, which are used to define and undefine, respectively, conditional compilation
38symbols (§9.5.3).
39• #if, #elif, #else, and #endif, which are used to conditionally skip sections of source code (§9.5.1).
40• #line, which is used to control line numbers emitted for errors and warnings (§9.5.7).
41• #error and #warning, which are used to issue errors and warnings, respectively (§9.5.5).
42• #region and #endregion, which are used to explicitly mark sections of source code (§9.5.6).
43• #pragma, which is used to provide contextual information to a compiler (§9.5.8).
75
C# LANGUAGE SPECIFICATION
1A pre-processing directive always occupies a separate line of source code and always begins with a
2# character and a pre-processing directive name. White space can occur before the # character and between
3the # character and the directive name.
4A source line containing a #define, #undef, #if, #elif, #else, #endif, or #line directive can end
5with a single-line comment. Delimited comments (the /* */ style of comments) are not permitted on source
6lines containing pre-processing directives.
7Pre-processing directives are not tokens and are not part of the syntactic grammar of C#. However, pre-
8processing directives can be used to include or exclude sequences of tokens and can in that way affect the
9meaning of a C# program. [Example: When compiled, the program
10#define A
11#undef B
12class C
13{
14#if A
15void F() {}
16#else
17void G() {}
18#endif
19#if B
20void H() {}
21#else
22void I() {}
23#endif
24}
25results in the exact same sequence of tokens as the program
26class C
27{
28 |
void F() {} |
29void I() {}
30}
31Thus, whereas lexically, the two programs are quite different, syntactically, they are identical. end example]
329.5.1 Conditional compilation symbols
33The conditional compilation functionality provided by the #if, #elif, #else, and #endif directives is
34controlled through pre-processing expressions (§9.5.2) and conditional compilation symbols.
35conditional-symbol::
36 |
Any identifier-or-keyword except true or false |
37A conditional compilation symbol has two possible states: defined or undefined. At the beginning of the
38lexical processing of a source file, a conditional compilation symbol is undefined unless it has been
39explicitly defined by an external mechanism (such as a command-line compiler option). When a #define
40directive is processed, the conditional compilation symbol named in that directive becomes defined in that
41source file. The symbol remains defined until an #undef directive for that same symbol is processed, or
42until the end of the source file is reached. An implication of this is that #define and #undef directives in
43one source file have no effect on other source files in the same program.
44The name space for conditional compilation symbols is distinct and separate from all other named entities in
45a C# program. Conditional compilation symbols can only be referenced in #define and #undef directives
46and in pre-processing expressions.
479.5.2 Pre-processing expressions
48Pre-processing expressions can occur in #if and #elif directives. The operators !, ==, !=, && and || are
49permitted in pre-processing expressions, and parentheses can be used for grouping.
76
|
|
|
Chapter 9 Lexical structure |
1 |
pp-expression:: |
|
|
2 |
whitespaceopt pp-or-expression whitespaceopt |
|
|
3 |
pp-or-expression:: |
|
|
4 |
pp-and-expression |
|
|
5 |
pp-or-expression whitespaceopt || |
whitespaceopt |
pp-and-expression |
6 |
pp-and-expression:: |
|
|
7 |
pp-equality-expression |
|
|
8 |
pp-and-expression whitespaceopt && |
whitespaceopt |
pp-equality-expression |
9 |
pp-equality-expression:: |
|
|
10 |
pp-unary-expression |
|
|
11 |
pp-equality-expression whitespaceopt |
== whitespaceopt pp-unary-expression |
|
12 |
pp-equality-expression whitespaceopt |
!= whitespaceopt pp-unary-expression |
|
13 |
pp-unary-expression:: |
|
|
14 |
pp-primary-expression |
|
|
15! whitespaceopt pp-unary-expression
16pp-primary-expression::
17 |
true |
18 |
false |
19 |
conditional-symbol |
20 |
( whitespaceopt pp-expression whitespaceopt ) |
21When referenced in a pre-processing expression, a defined conditional compilation symbol has the boolean
22value true, and an undefined conditional compilation symbol has the boolean value false.
23Evaluation of a pre-processing expression always yields a boolean value. The rules of evaluation for a pre-
24processing expression are the same as those for a constant expression (§14.15), except that the only user-
25defined entities that can be referenced are conditional compilation symbols.
269.5.3 Declaration directives
27The declaration directives are used to define or undefine conditional compilation symbols.
28pp-declaration::
29 |
whitespaceopt # |
whitespaceopt |
define whitespace conditional-symbol pp-new-line |
|
30 |
whitespaceopt |
# |
whitespaceopt |
undef whitespace conditional-symbol pp-new-line |
31 |
pp-new-line:: |
|
|
|
32 |
whitespaceopt |
single-line-commentopt new-line |
||
33The processing of a #define directive causes the given conditional compilation symbol to become defined,
34starting with the source line that follows the directive. Likewise, the processing of an #undef directive
35causes the given conditional compilation symbol to become undefined, starting with the source line that
36follows the directive.
37Any #define and #undef directives in a source file shall occur before the first token (§9.4) in the source
38file; otherwise a compile-time error occurs. In intuitive terms, #define and #undef directives shall
39precede any “real code” in the source file.
40[Example: The example:
41#define Enterprise
42#if Professional || Enterprise
43#define Advanced
44#endif
77
C# LANGUAGE SPECIFICATION
1namespace Megacorp.Data
2{
3 |
#if Advanced |
4 |
class PivotTable {...} |
5#endif
6}
7is valid because the #define directives precede the first token (the namespace keyword) in the source file.
8end example]
9[Example: The following example results in a compile-time error because a #define follows real code:
10#define A
11namespace N
12{
13 |
#define B |
14 |
#if B |
15 |
class Class1 {} |
16#endif
17}
18end example]
19A #define can define a conditional compilation symbol that is already defined, without there being any
20intervening #undef for that symbol. [Example: The example below defines a conditional compilation
21symbol A and then defines it again.
22#define A
23#define A
24For compilers that allow conditional compilation symbols to be defined as compilation options, an
25alternative way for such redefinition to occur is to define the symbol as a compiler option as well as in the
26source. end example]
27A #undef can “undefine” a conditional compilation symbol that is not defined. [Example: The example
28below defines a conditional compilation symbol A and then undefines it twice; although the second #undef
29has no effect, it is still valid.
30#define A
31#undef A
32#undef A
33end example]
349.5.4 Conditional compilation directives
35The conditional compilation directives are used to conditionally include or exclude portions of a source file.
36pp-conditional::
37 |
pp-if-section pp-elif-sectionsopt |
pp-else-sectionopt |
pp-endif |
38 |
pp-if-section:: |
|
|
39 |
whitespaceopt # whitespaceopt if whitespace pp-expression pp-new-line |
||
40 |
conditional-sectionopt |
|
|
41 |
pp-elif-sections:: |
|
|
42 |
pp-elif-section |
|
|
43 |
pp-elif-sections pp-elif-section |
|
|
44 |
pp-elif-section:: |
|
|
45 |
whitespaceopt # whitespaceopt elif whitespace pp-expression pp-new-line |
||
46 |
conditional-sectionopt |
|
|
47 |
pp-else-section:: |
|
|
48 |
whitespaceopt # whitespaceopt |
else pp-new-line |
conditional-sectionopt |
78
Chapter 9 Lexical structure
1 |
pp-endif:: |
2 |
whitespaceopt # whitespaceopt endif pp-new-line |
3 |
conditional-section:: |
4 |
input-section |
5 |
skipped-section |
6 |
skipped-section:: |
7 |
skipped-section-part |
8 |
skipped-section skipped-section-part |
9 |
skipped-section-part:: |
10 |
whitespaceopt skipped-charactersopt new-line |
11 |
pp-directive |
12 |
skipped-characters:: |
13 |
not-number-sign input-charactersopt |
14 |
not-number-sign:: |
15 |
Any input-character except # |
16[Note: As indicated by the syntax, conditional compilation directives shall be written as sets consisting of, in
17order, an #if directive, zero or more #elif directives, zero or one #else directive, and an #endif
18directive. Between the directives are conditional sections of source code. Each section is controlled by the
19immediately preceding directive. A conditional section can itself contain nested conditional compilation
20directives provided these directives form complete sets. end note]
21A pp-conditional selects at most one of the contained conditional-sections for normal lexical processing:
22• The pp-expressions of the #if and #elif directives are evaluated in order until one yields true. If an
23expression yields true, the conditional-section of the corresponding directive is selected.
24• If all pp-expressions yield false, and if an #else directive is present, the conditional-section of the
25#else directive is selected.
26• Otherwise, no conditional-section is selected.
27The selected conditional-section, if any, is processed as a normal input-section: the source code contained in
28the section shall adhere to the lexical grammar; tokens are generated from the source code in the section; and
29pre-processing directives in the section have the prescribed effects.
30The remaining conditional-sections, if any, are processed as skipped-sections: except for pre-processing
31directives, the source code in the section need not adhere to the lexical grammar; no tokens are generated
32from the source code in the section; and pre-processing directives in the section shall be lexically correct but
33are not otherwise processed. Within a conditional-section that is being processed as a skipped-section, any
34nested conditional-sections (contained in nested #if...#endif and #region...#endregion constructs) are
35also processed as skipped-sections.
36[Example: The following example illustrates how conditional compilation directives can nest:
37 |
#define Debug |
// |
Debugging on |
38 |
#undef Trace |
// |
Tracing off |
39class PurchaseTransaction
40{
41 |
void Commit() { |
42 |
#if Debug |
43 |
CheckConsistency(); |
44 |
#if Trace |
45 |
WriteToLog(this.ToString()); |
46 |
#endif |
47 |
#endif |
48 |
CommitHelper(); |
49 |
} |
50…
51}
79
