C# Language Standard

repository·draft-v8·Indexed 21 days ago

https://github.com/dotnet/csharpstandard

The working space for the ECMA-TC49-TG2 committee, containing the C# language specification in Markdown format for versions 5 through 9. It includes detailed documentation on lexical structure, the type system, nullability, variable categories, conversions, pattern matching, and async functions, as well as tooling like GetGrammar, ExampleExtractor, and ExampleTester for maintaining and validating the standard.

Tokens
197.5K
Snippets
442
Records
715
Agent score
70%

What's inside csharpstandard

  1. Understand the structure of the C# Language Specification

    draft-v8

    The C# Language Specification is organized into three main subdivisions:

    1. Front matter: Introductory information.
    2. Language syntax, constraints, and semantics: The core technical definitions of the language.
    3. Annexes: Additional information and summaries of the specification content.

    When reading the specification, distinguish between normative text (the actual rules of the language) and informative text (explanations, examples, and guidance).

  2. Understand the C# Language Specification structure

    draft-v8

    The C# Language Specification is organized into several major sections that define how the language is structured, parsed, and executed. Key areas include:

    • Lexical Structure (§6): Defines the basic building blocks of the language, including programs, grammars, lexical analysis, tokens (identifiers, keywords, literals), and pre-processing directives.
    • Basic Concepts (§7): Covers fundamental execution models like application startup/termination, declarations, member access (accessibility domains), and scopes.
    • Types (§8): Details the type system, including reference types (classes, interfaces, arrays), value types (structs, enums, tuples), constructed types (generics), and nullability (non-nullable and nullable reference types).
    • Variables (§9): Explains variable categories (static, instance, local, parameters), default values, and the rules for Definite Assignment.
  3. Understand the scope of the C# Language Specification

    draft-v8

    The C# Language Specification defines the formal structure and interpretation of C# programs. It is divided into what the specification covers and what it explicitly excludes.

    What is covered:

    • Program Representation: How C# programs are structured.
    • Syntax and Constraints: The formal grammar and rules of the language.
    • Semantic Rules: The logic and rules used to interpret C# programs.
    • Implementation Limits: The restrictions and boundaries imposed on any conforming C# implementation.

    What is NOT covered:

    • Transformation Mechanisms: How programs are transformed for use by data-processing systems.
    • Invocation Mechanisms: How C# applications are started or invoked.
    • Data Transformation: How input data is prepared for an application or how output data is processed after production.
    • System Capacity: The size or complexity limits of programs/data relative to specific hardware or processors.
    • System Requirements: The minimal hardware or software requirements for a data-processing system to support a conforming C# implementation.
  4. Understand C# Language Core Concepts

    draft-v8

    The C# Language Standard defines the syntax and semantics for various language constructs. Key areas of the specification include:

    • Classes and Members: Properties, events, indexers, operators, constructors, finalizers, and async functions.
    • Value Types: Structs, enums, and arrays.
    • Abstraction and Polymorphism: Interfaces, delegates, and inheritance.
    • Control Flow and Error Handling: Exceptions.
    • Metadata: Attributes.
    • Advanced Indexing: Ranges and extended indexing/slicing.

    Refer to the specific sections of the specification for detailed rules on each construct.

  5. Identify new features in the C# language specification

    draft-v8

    This specification replaces ECMA-334:2023. If you are migrating from an older version of the C# standard, the following features have been added in this edition:

    • Strings: enhanced interpolated verbatim strings
    • Asynchronous Programming: asynchronous streams, using declarations, and async using
    • Generics & Types: generic method override with constraints, unmanaged constructed types, and notnull constraint
    • Interfaces: default member implementations in interfaces
    • Memory & Performance: permit stackalloc in nested contexts and Disposable ref structs
    • Null Safety: nullable reference types and null coalescing assignment
    • Pattern Matching: positional, property, and discard patterns
    • Collections & Indexing: ranges and indexes
    • Members & Scope: readonly instance members, name shadowing in nested functions, and static local functions
  6. What is a constant expression in C#

    draft-v8

    A constant expression is an expression that must be fully evaluated at compile-time. When an expression meets the requirements for a constant expression, it is evaluated during compilation, even if it is a subexpression of a larger expression containing non-constant constructs.

    Key Characteristics:

    • Compile-time evaluation: Uses the same rules as run-time evaluation, but instead of throwing exceptions, it triggers compile-time errors.
    • Overflow behavior: Unless explicitly placed in an unchecked context, integral-type arithmetic overflows during compile-time evaluation cause compile-time errors.
    • Permitted Types: A constant expression must result in null or one of the following types:
      • sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, string
      • An enumeration type
      • A default value expression for a reference type
    // Example of valid constant expressions
    const int x = 5 + 5; // Evaluated at compile-time
    const string s = "hello";
    const MyEnum e = MyEnum.Value;
  7. Overview of extended indexing and slicing

    draft-v8

    C# provides a model for extended indexable and sliceable collections using System.Index and System.Range. This model allows for more expressive ways to access elements and sub-sections of collections like arrays and strings.

    Key Concepts

    • Collection: A type representing a group of elements.
    • Countable Collection: A collection that provides a Length or Count property (an int).
    • Sequence / Indexable Type: A countable collection where elements can be accessed via an element_access expression using an int (from-start index).
    • Extended Indexable: A type that supports element_access using a System.Index argument.
    • Sliceable Collection: A collection that provides a Slice(int index, int count) method.
    • Extended Sliceable: A type that supports element_access using a System.Range argument.

    Requirements for Implementation

    To implement this model in your own types, you can provide appropriate indexers. A type can inherit these capabilities; for example, a class providing Length is countable, a derived class providing an int indexer is a sequence, and a further derived class providing a Slice method is sliceable.

  8. What is a boolean expression

    draft-v8

    A boolean_expression is an expression that yields a result of type bool.

    Usage in Control Flow:

    • The controlling conditional expression of if, while, do, and for statements must be a boolean_expression.
    • The ?: (conditional) operator uses a boolean_expression for its condition, though it is technically classified as a null_coalescing_expression due to operator precedence.

    Resolution Logic:

    1. If the expression is implicitly convertible to bool, the conversion is applied at run-time.
    2. Otherwise, the compiler uses unary operator overload resolution to find a unique best implementation of operator true on the expression.
    3. If no such operator is found, a binding-time error occurs.
  9. Overview of C# Pre-processing Directives

    draft-v8

    Pre-processing directives in C# allow you to conditionally skip sections of code, report errors/warnings, delineate code regions, and manage the nullable context. Unlike C or C++, these are processed during the lexical analysis phase rather than in a separate pre-processing step.

    Key Rules:

    • Directives always occupy a separate line.
    • They always begin with a # character (whitespace is allowed before the # and between the # and the directive name).
    • #define, #undef, #if, #elif, #else, #endif, #line, #endregion, and #nullable directives can end with a single-line comment (//).
    • Delimited comments (/* */) are not permitted on the same line as a pre-processing directive.
    • Directives are not part of the syntactic grammar, but they can affect the meaning of a program by including or excluding tokens.
    #define A
    #undef B
    class C
    {
    #if A
        void F() {}
    #else
        void G() {}
    #endif
    }
  10. Overview of Implicit Conversions in C#

    draft-v8

    Implicit conversions allow a value of one type to be used where another type is expected without an explicit cast. These conversions can occur during function member invocations, cast expressions, and assignments. Pre-defined implicit conversions are guaranteed to succeed and never throw exceptions.

    Key categories of implicit conversions include:

    • Identity conversions: Converting a type to itself or an equivalent type.
    • Numeric conversions: Converting between compatible numeric types (e.g., int to long).
    • Reference conversions: Converting between reference types (e.g., derived class to base class).
    • Boxing: Converting a value type to a reference type.
    • Dynamic conversions: Converting dynamic expressions to other types at runtime.
    • Nullable conversions: Converting between nullable and non-nullable versions of types.
  11. Obtain values from variables, properties, indexers, and tuples

    draft-v8

    When a construct requires an expression to denote a value, the following substitution rules apply:

    • Variables: The value currently stored in the variable's storage location. The variable must be definitely assigned before its value is obtained.
    • Property access: Obtained by invoking the get accessor. If no get accessor exists, a compile-time error occurs.
    • Indexer access: Obtained by invoking the get accessor with the associated argument list. If no get accessor exists, a compile-time error occurs.
    • Tuple literal (with a type): Obtained by evaluating each element expression in order from left to right. Note that obtaining the value of a tuple literal that does not have a type is an error.
  12. Definite-assignment rules for && (Logical AND) expressions

    draft-v8

    For the expression expr_first && expr_second:

    • The state of v before expr_first is the same as before the expression.
    • v is definitely assigned before expr_second if and only if the state after expr_first is either 'definitely assigned' or 'definitely assigned after true expression'.
    • The state after the whole expression depends on the states after expr_first and expr_second. For example, if expr_first results in 'definitely assigned after false expression' and expr_second results in 'definitely assigned', the final state is 'definitely assigned'.

    Example of conditional assignment:

    class A
    {
        static void F(int x, int y)
        {
            int i;
            if (x >= 0 && (i = y) >= 0)
            {
                // i is definitely assigned here because (i = y) always executes
            }
            else
            {
                // i is NOT definitely assigned here because x >= 0 might be false
            }
        }
    }
    class A
    {
        static void F(int x, int y)
        {
            int i;
            if (x >= 0 && (i = y) >= 0)
            {
                // i definitely assigned
            }
            else
            {
                // i not definitely assigned
            }
            // i not definitely assigned
        }
    }