C# Docs
C# Docs
C# Docs
C# documentation
Get started
Overview
Introduction to the C# language and the .NET framework
Tutorials
Overview
Introduction to programming with C#
Choose your first lesson
Hello world
Numbers in C#
Branches and loops
List collections
Work in your local environment
Set up your environment
Numbers in C#
Branches and loops
List collections
Introduction to classes
Explore C# 6
Explore string interpolation - interactive
Explore string interpolation - in your environment
Advanced scenarios for string Interpolation
Safely update interfaces with default interface methods
Create mixin functionality with default interface methods
Explore indexes and ranges
Work with nullable reference types
Upgrade an app to nullable reference types
Generate and consume asynchronous streams
Extend data capabilities using pattern matching
Console Application
REST Client
Inheritance in C# and .NET
Work with LINQ
Use Attributes
Tour of C#
Introduction
Types
Program building blocks
Major language areas
What's new in C#
C# 8.0
C# 7.3
C# 7.2
C# 7.1
C# 7.0
C# 6
Breaking changes in the compiler
C# Version History
Relationships between language and framework
Version and update considerations
C# concepts
C# type system
Nullable reference types
Choose a strategy for enabling nullable reference types
Namespaces
Basic Types
Classes
Deconstructing tuples and other types
Interfaces
Methods
Properties
Indexers
Discards
Generics
Iterators
Delegates & events
Introduction to Delegates
System.Delegate and the delegate keyword
Strongly Typed Delegates
Common Patterns for Delegates
Introduction to events
Standard .NET event patterns
The Updated .NET Event Pattern
Distinguishing Delegates and Events
Language-Integrated Query (LINQ)
Overview of LINQ
Query expression basics
LINQ in C#
Write LINQ queries in C#
Query a collection of objects
Return a query from a method
Store the results of a query in memory
Group query results
Create a nested group
Perform a subquery on a grouping operation
Group results by contiguous keys
Dynamically specify predicate filters at runtime
Perform inner joins
Perform grouped joins
Perform left outer joins
Order the results of a join clause
Join by using composite keys
Perform custom join operations
Handle null values in query expressions
Handle exceptions in query expressions
Asynchronous programming
Pattern Matching
Write safe, efficient code
Expression trees
Introduction to expression trees
Expression Trees Explained
Framework Types Supporting Expression Trees
Executing Expressions
Interpreting Expressions
Building Expressions
Translating Expressions
Summary
Native interoperability
Documenting your code
Versioning
How-to C# articles
Article index
Parse strings using `String.Split`
Concatenate strings
Search strings
Modify string contents
Compare strings
Safely cast using pattern matching, is and as operators
The .NET Compiler Platform SDK (Roslyn APIs)
The .NET Compiler Platform SDK (Roslyn APIs) overview
Understand the compiler API model
Work with syntax
Work with semantics
Work with a workspace
Explore code with the syntax visualizer
Quick starts
Syntax analysis
Semantic analysis
Syntax Transformation
Tutorials
Build your first analyzer and code fix
C# programming guide
Overview
Inside a C# program
What's inside a C# program
Hello World -- Your First Program
General Structure of a C# Program
Identifier names
C# Coding Conventions
Main() and command-line arguments
Overview
Command-Line Arguments
How to display command-line arguments
Main() Return Values
Programming concepts
Overview
Asynchronous programming
Overview
Task asynchronous programming model
Async return types
Cancel tasks
Cancel a list of tasks
Cancel tasks after a period of time
Process asynchronous tasks as they complete
Asynchronous file access
Attributes
Overview
Creating Custom Attributes
Accessing Attributes by Using Reflection
How to create a C/C++ union by using attributes
Collections
Covariance and contravariance
Overview
Variance in Generic Interfaces
Create Variant Generic Interfaces
Use Variance in Interfaces for Generic Collections
Variance in Delegates
Use Variance in Delegates
Use Variance for Func and Action Generic Delegates
Expression trees
Overview
How to execute expression trees
How to modify expression trees
How to use expression trees to build dynamic queries
Debugging Expression Trees in Visual Studio
DebugView Syntax
Iterators
Language-Integrated Query (LINQ)
Overview
Getting Started with LINQ in C#
Introduction to LINQ Queries
LINQ and Generic Types
Basic LINQ Query Operations
Data Transformations with LINQ
Type Relationships in LINQ Query Operations
Query Syntax and Method Syntax in LINQ
C# Features That Support LINQ
Walkthrough: Writing Queries in C# (LINQ)
Standard Query Operators Overview
Overview
Query Expression Syntax for Standard Query Operators
Classification of Standard Query Operators by Manner of Execution
Sorting Data
Set Operations
Filtering Data
Quantifier Operations
Projection Operations
Partitioning Data
Join Operations
Grouping Data
Generation Operations
Equality Operations
Element Operations
Converting Data Types
Concatenation Operations
Aggregation Operations
LINQ to Objects
Overview
LINQ and Strings
How to articles
How to count occurrences of a word in a string (LINQ)
How to query for sentences that contain a specified set of words (LINQ)
How to query for characters in a string (LINQ)
How to combine LINQ queries with regular expressions
How to find the set difference between two lists (LINQ)
How to sort or filter text data by any word or field (LINQ)
How to reorder the fields of a delimited file (LINQ)
How to combine and compare string collections (LINQ)
How to populate object collections from multiple sources (LINQ)
How to split a file into many files by using groups (LINQ)
How to join content from dissimilar files (LINQ)
How to compute column values in a CSV text file (LINQ)
LINQ and Reflection
How to query an assembly's metadata with Reflection (LINQ)
LINQ and File Directories
Overview
How to query for files with a specified attribute or name
How to group files by extension (LINQ)
How to query for the total number of bytes in a set of folders (LINQ)
How to compare the contents of two folders (LINQ)
How to query for the largest file or files in a directory tree (LINQ)
How to query for duplicate files in a directory tree (LINQ)
How to query the contents of files in a folder (LINQ)
How to query an ArrayList with LINQ
How to add custom methods for LINQ queries
LINQ to XML
Getting Started (LINQ to XML)
LINQ to XML Overview
LINQ to XML vs. DOM
LINQ to XML vs. Other XML Technologies
Programming Guide (LINQ to XML)
LINQ to XML Programming Overview
XML Trees
Working with XML Namespaces
Serializing XML Trees
LINQ to XML Axes
Querying XML Trees
Modifying XML Trees (LINQ to XML)
Performance (LINQ to XML)
Advanced LINQ to XML Programming
LINQ to XML Security
Sample XML Documents (LINQ to XML)
Reference (LINQ to XML)
LINQ to ADO.NET (Portal Page)
Enabling a Data Source for LINQ Querying
Visual Studio IDE and Tools Support for LINQ
Object-Oriented Programming
Reflection
Serialization (C#)
Overview
How to write object data to an XML file
How to read object data from an XML file
Walkthrough: Persisting an Object in Visual Studio
Statements, expressions, and operators
Overview
Statements
Expression-bodied members
Anonymous functions
Overview
How to use lambda expressions in a query
Equality and equality comparisons
Equality comparisons
How to define value equality for a type
How to test for reference equality (identity)
Types
Use and define types
Casting and Type Conversions
Boxing and Unboxing
How to convert a byte array to an int
How to convert a string to a number
How to convert between hexadecimal strings and numeric types
Using Type dynamic
Walkthrough: Creating and Using Dynamic Objects (C# and Visual Basic)
Classes and Structs
Overview
Classes
Objects
Inheritance
Polymorphism
Overview
Versioning with the Override and New Keywords
Knowing When to Use Override and New Keywords
How to override the ToString method
Members
Members overview
Abstract and Sealed Classes and Class Members
Static Classes and Static Class Members
Access Modifiers
Fields
Constants
How to define abstract properties
How to define constants in C#
Properties
Properties overview
Using Properties
Interface Properties
Restricting Accessor Accessibility
How to declare and use read write properties
Auto-Implemented Properties
How to implement a lightweight class with auto-implemented properties
Methods
Methods overview
Local functions
Ref returns and ref locals
Parameters
Passing parameters
Passing Value-Type Parameters
Passing Reference-Type Parameters
How to know the difference between passing a struct and passing a class
reference to a method
Implicitly Typed Local Variables
How to use implicitly typed local variables and arrays in a query expression
Extension Methods
How to implement and call a custom extension method
How to create a new method for an enumeration
Named and Optional Arguments
How to use named and optional arguments in Office programming
Constructors
Constructors overview
Using Constructors
Instance Constructors
Private Constructors
Static Constructors
How to write a copy constructor
Finalizers
Object and Collection Initializers
How to initialize objects by using an object initializer
How to initialize a dictionary with a collection initializer
Nested Types
Partial Classes and Methods
Anonymous Types
How to return subsets of element properties in a query
Interfaces
Overview
Explicit Interface Implementation
How to explicitly implement interface members
How to explicitly implement members of two interfaces
Delegates
Overview
Using Delegates
Delegates with Named vs. Anonymous Methods
How to combine delegates (Multicast Delegates) (C# Programming Guide)
How to declare, instantiate, and use a delegate
Arrays
Overview
Arrays as Objects
Single-Dimensional Arrays
Multidimensional Arrays
Jagged Arrays
Using foreach with Arrays
Passing Arrays as Arguments
Implicitly Typed Arrays
Strings
Programming with strings
How to determine whether a string represents a numeric value
Indexers
Overview
Using Indexers
Indexers in Interfaces
Comparison Between Properties and Indexers
Events
Overview
How to subscribe to and unsubscribe from events
How to publish events that conform to .NET Framework Guidelines
How to raise base class events in derived classes
How to implement interface events
How to implement custom event accessors
Generics
Overview
Generic Type Parameters
Constraints on Type Parameters
Generic Classes
Generic Interfaces
Generic Methods
Generics and Arrays
Generic Delegates
Differences Between C++ Templates and C# Generics
Generics in the Run Time
Generics and Reflection
Generics and Attributes
Namespaces
Overview
Using namespaces
How to use the My namespace
Unsafe Code and Pointers
Overview and restrictions
Fixed size buffers
Pointer types
Overview
Pointer conversions
How to use pointers to copy an array of bytes
XML documentation comments
Overview
Recommended tags for documentation comments
Processing the XML file
Delimiters for documentation tags
How to use the XML documentation features
Documentation tag reference
<c>
<code>
cref attribute
<example>
<exception>
<include>
<inheritdoc>
<list>
<para>
<param>
<paramref>
<permission>
<remarks>
<returns>
<see>
<seealso>
<summary>
<typeparam>
<typeparamref>
<value>
Exceptions and Exception Handling
Overview
Using Exceptions
Exception Handling
Creating and Throwing Exceptions
Compiler-Generated Exceptions
How to handle an exception using try-catch
How to execute cleanup code using finally
How to catch a non-CLS exception
File System and the Registry
Overview
How to iterate through a directory tree
How to get information about files, folders, and drives
How to create a file or folder
How to copy, delete, and move files and folders
How to provide a progress dialog box for file operations
How to write to a text file
How to read From a text file
How to read a text file one line at a time
How to create a key in the registry
Interoperability
.NET Interoperability
Interoperability Overview
How to access Office interop objects by using C# features
How to use indexed properties in COM interop programming
How to use platform invoke to play a WAV file
Walkthrough: Office Programming (C# and Visual Basic)
Example COM Class
Language reference
Overview
Configure language version
Types
Value types
Overview
Integral numeric types
Floating-point numeric types
Built-in numeric conversions
bool
char
Enumeration types
Structure types
Tuple types
Nullable value types
Reference types
Features of reference types
Built-in reference types
class
interface
Nullable reference types
void
var
Built-in types
Unmanaged types
Default values
Keywords
Overview
Modifiers
Access Modifiers
Quick reference
Accessibility Levels
Accessibility Domain
Restrictions on Using Accessibility Levels
internal
private
protected
public
protected internal
private protected
abstract
async
const
event
extern
in (generic modifier)
new (member modifier)
out (generic modifier)
override
readonly
sealed
static
unsafe
virtual
volatile
Statement Keywords
Statement categories
Selection Statements
if-else
switch
Iteration Statements
do
for
foreach, in
while
Jump Statements
break
continue
goto
return
Exception Handling Statements
throw
try-catch
try-finally
try-catch-finally
Checked and Unchecked
Overview
checked
unchecked
fixed Statement
lock Statement
Method Parameters
Passing parameters
params
in (Parameter Modifier)
ref
out (Parameter Modifier)
Namespace Keywords
namespace
using
Contexts for using
using Directive
using static Directive
using Statement
extern alias
Type-testing Keywords
is
Generic Type Constraint Keywords
new constraint
where
Access Keywords
base
this
Literal Keywords
null
true and false
default
Contextual Keywords
Quick reference
add
get
partial (Type)
partial (Method)
remove
set
when (filter condition)
value
yield
Query Keywords
Quick reference
from clause
where clause
select clause
group clause
into
orderby clause
join clause
let clause
ascending
descending
on
equals
by
in
Operators and expressions
Overview
Arithmetic operators
Boolean logical operators
Bitwise and shift operators
Equality operators
Comparison operators
Member access operators and expressions
Type-testing operators and cast expression
User-defined conversion operators
Pointer-related operators
Assignment operators
Lambda expressions
+ and += operators
- and -= operators
?: operator
! (null-forgiving) operator
?? and ??= operators
=> operator
:: operator
await operator
default value expressions
delegate operator
nameof expression
new operator
sizeof operator
stackalloc expression
switch expression
true and false operators
Operator overloading
Special characters
Overview
$ -- string interpolation
@ -- verbatim identifier
Attributes read by the compiler
Global attributes
General
Caller information
Nullable static analysis
Preprocessor directives
Overview
#if
#else
#elif
#endif
#define
#undef
#warning
#error
#line
#region
#endregion
#pragma
#pragma warning
#pragma checksum
Compiler options
Overview
Command-line Building With csc.exe
How to set environment variables for the Visual Studio Command Line
C# Compiler Options Listed by Category
C# Compiler Options Listed Alphabetically
@
-addmodule
-appconfig
-baseaddress
-bugreport
-checked
-codepage
-debug
-define
-delaysign
-deterministic
-doc
-errorreport
-filealign
-fullpaths
-help, -?
-highentropyva
-keycontainer
-keyfile
-langversion
-lib
-link
-linkresource
-main
-moduleassemblyname
-noconfig
-nologo
-nostdlib
-nowarn
-nowin32manifest
-nullable
-optimize
-out
-pathmap
-pdb
-platform
-preferreduilang
-publicsign
-recurse
-reference
-refout
-refonly
-resource
-subsystemversion
-target
-target:appcontainerexe
-target:exe
-target:library
-target:module
-target:winexe
-target:winmdobj
-unsafe
-utf8output
-warn
-warnaserror
-win32icon
-win32manifest
-win32res
Compiler errors
C# 6.0 draft specification
C# 7.0 - 9.0 proposals
Walkthroughs
Get started with C#
9/3/2020 • 2 minutes to read • Edit Online
This section provides short, simple tutorials that let you quickly build an application using C# and .NET Core. There
are getting started topics for Visual Studio and Visual Studio Code. These articles assume some programming
experience. If you are new to programming, try our introduction to C# interactive tutorials.
The following topics are available:
Introduction to the C# language and the .NET Framework
Provides an overview of the C# language and .NET.
Create a C# Hello World application with .NET Core in Visual Studio
Visual Studio lets you code, compile, run, debug, profile, and publish your applications from an integrated
development environment for Windows or Mac.
The topic lets you create and run a simple Hello World application, and then modify it to run a slightly more
interactive Hello World application. Once you've finished building and running your application, you can also
learn how to debug it and how to publish it so that it can be run on any platform supported by .NET Core.
Create a class library with C# and .NET Standard in Visual Studio
A class library lets you define types and type members that can be called from another application. This
topic lets you create a class library with a single method that determines whether a string begins with an
uppercase character. Once you've finished building the library, you can develop a unit test to ensure that it
works as expected, and then you can make it available to applications that want to consume it.
Get started with C# and Visual Studio Code
Visual Studio Code is a free code editor optimized for building and debugging modern web and cloud
applications. It supports IntelliSense and is available for Linux, macOS, and Windows.
This topic shows you how to create and run a simple Hello World application with Visual Studio Code and
.NET Core.
Related sections
C# Programming Guide
Provides information about C# programming concepts, and describes how to perform various tasks in C#.
C# Reference
Provides detailed reference information about C# keywords, operators, preprocessor directives, compiler
options, and compiler errors and warnings.
Walkthroughs
Provides links to programming walkthroughs that use C# and a brief description of each walkthrough.
See also
C# Development with Visual Studio
Introduction to the C# language and .NET
Framework
9/3/2020 • 4 minutes to read • Edit Online
C# is an elegant and type-safe object-oriented language that enables developers to build a variety of secure and
robust applications that run in the .NET ecosystem. The .NET ecosystem is composed of all the implementations of
.NET, including both but not limited to .NET Core, and .NET Framework. This article focuses on .NET Framework. You
can use C# to create Windows client applications, XML Web services, distributed components, client-server
applications, database applications, and much, much more.
NOTE
The Visual C# documentation assumes that you have an understanding of basic programming concepts. If you are a
complete beginner, you might want to explore Visual C# Express, which is available on the Web. You can also take advantage
of books and Web resources about C# to learn practical programming skills.
C# language
C# syntax is highly expressive, yet it is also simple and easy to learn. The curly brace syntax of C# will be instantly
recognizable to anyone familiar with C, C++, or Java. Developers who know any of these languages are typically
able to begin to work productively in C# within a short time. C# syntax simplifies many of the complexities of C++
and provides powerful features such as nullable types, enumerations, delegates, lambda expressions, and direct
memory access. C# supports generic methods and types, which provide increased type safety and performance,
and iterators, which enable implementers of collection classes to define custom iteration behaviors that are simple
to use by client code. Language-Integrated Query (LINQ) expressions make the strongly typed query a first-class
language construct.
As an object-oriented language, C# supports the concepts of encapsulation, inheritance, and polymorphism. All
variables and methods, including the Main method, the application's entry point, are encapsulated within class
definitions. A class may inherit directly from one parent class, but it may implement any number of interfaces.
Methods that override virtual methods in a parent class require the override keyword as a way to avoid accidental
redefinition. In C#, a struct is like a lightweight class; it is a stack-allocated type that can implement interfaces but
does not support inheritance.
In addition to these basic object-oriented principles, C# makes it easy to develop software components through
several innovative language constructs, including the following:
Encapsulated method signatures called delegates, which enable type-safe event notifications.
Properties, which serve as accessors for private member variables.
Attributes, which provide declarative metadata about types at run time.
Inline XML documentation comments.
Language-Integrated Query (LINQ), which provides built-in query capabilities across a variety of data sources.
If you have to interact with other Windows software such as COM objects or native Win32 DLLs, you can do this in
C# through a process called "Interop". Interop enables C# programs to do almost anything that a native C++
application can do. C# even supports pointers and the concept of "unsafe" code for those cases in which direct
memory access is critical.
The C# build process is simple compared to C and C++ and more flexible than in Java. There are no separate
header files, and no requirement that methods and types be declared in a particular order. A C# source file may
define any number of classes, structs, interfaces, and events.
The following are additional C# resources:
For a good general introduction to the language, see Chapter 1 of the C# Language Specification.
For detailed information about specific aspects of the C# language, see the C# Reference.
For more information about LINQ, see LINQ (Language-Integrated Query).
Language interoperability is a key feature of the .NET Framework. Because the IL code produced by the C#
compiler conforms to the Common Type Specification (CTS), IL code generated from C# can interact with code that
was generated from the .NET versions of Visual Basic, Visual C++, or any of more than 20 other CTS-compliant
languages. A single assembly may contain multiple modules written in different .NET languages, and the types can
reference each other as if they were written in the same language.
In addition to the run time services, the .NET Framework also includes an extensive library of over 4000 classes
organized into namespaces that provide a wide variety of useful functionality for everything from file input and
output to string manipulation to XML parsing, to Windows Forms controls. The typical C# application uses the .NET
Framework class library extensively to handle common "plumbing" chores.
For more information about the .NET Framework, see Overview of the Microsoft .NET Framework.
See also
Getting Started with Visual C#
C# Tutorials
9/3/2020 • 3 minutes to read • Edit Online
Welcome to the C# tutorials. These start with interactive lessons that you can run in your browser. Later tutorials
and more advanced tutorials help you work with the .NET development tools to create C# programs on your
machine.
Hello world
In the Hello world tutorial, you'll create the most basic C# program. You'll explore the string type and how to
work with text.
Numbers in C#
In the Numbers in C# tutorial, you'll learn how computers store numbers and how to perform calculations with
different numeric types. You'll learn the basics of rounding, and how to perform mathematical calculations using
C#. This tutorial is also available to run locally on your machine.
This tutorial assumes that you have finished the Hello world lesson.
List collection
The List collection lesson gives you a tour of the List collection type that stores sequences of data. You'll learn how
to add and remove items, search for items, and sort the lists. You'll explore different kinds of lists. This tutorial is
also available to run locally on your machine.
This tutorial assumes that you have finished the lessons listed above.
General Tutorials
The following tutorials enable you to build C# programs using .NET Core:
Console Application: demonstrates Console I/O, the structure of a Console application, and the basics of the
task-based asynchronous programming model.
REST Client: demonstrates web communications, JSON serialization, and object-oriented features in the C#
language.
Inheritance in C# and .NET: demonstrates inheritance in C#, including the use of inheritance to define base
classes, abstract base classes, and derived classes.
Working with LINQ: demonstrates many of the features of LINQ and the language elements that support it.
Using Attributes: demonstrates how to create and use attributes in C#.
String interpolation tutorial shows you how to insert values into a string. You'll learn how to create an
interpolated string with embedded C# expressions and how to control the text appearance of the expression
results in the result string. This tutorial is also available to run locally on your machine.
Introduction to C#
9/3/2020 • 2 minutes to read • Edit Online
Welcome to the introduction to C# tutorials. These lessons start with interactive code that you can run in your
browser. You can learn the basics of C# from the C# 101 video series before starting these interactive lessons.
The first lessons explain C# concepts using small snippets of code. You'll learn the basics of C# syntax and how to
work with data types like strings, numbers, and booleans. It's all interactive, and you'll be writing and running code
within minutes. These first lessons assume no prior knowledge of programming or the C# language.
You can try these tutorials in different environments. The concepts you'll learn are the same. The difference is
which experience you prefer:
In your browser, on the docs platform: This experience embeds a runnable C# code window in docs pages. You
write and execute C# code in the browser.
In the Microsoft Learn experience. This learning path contains several modules that teach the basics of C#.
In Jupyter on Binder. You can experiment with C# code in a Jupyter notebook on binder.
On your local machine. After you've explored online, you can download the .NET Core SDK and build programs
on your machine.
All the introductory tutorials following the Hello World lesson are available using the online browser experience or
in your own local development environment. At the end of each tutorial, you decide if you want to continue with
the next lesson online or on your own machine. There are links to help you set up your environment and continue
with the next tutorial on your machine.
Hello world
In the Hello world tutorial, you'll create the most basic C# program. You'll explore the string type and how to
work with text. You can also use the path on Microsoft Learn or Jupyter on Binder.
Numbers in C#
In the Numbers in C# tutorial, you'll learn how computers store numbers and how to perform calculations with
different numeric types. You'll learn the basics of rounding, and how to perform mathematical calculations using
C#. This tutorial is also available to run locally on your machine.
This tutorial assumes that you've finished the Hello world lesson.
List collection
The List collection lesson gives you a tour of the List collection type that stores sequences of data. You'll learn how
to add and remove items, search for items, and sort the lists. You'll explore different kinds of lists. This tutorial is
also available to run locally on your machine.
This tutorial assumes that you've finished the lessons listed above.
Introduction to classes
This final tutorial is only available to run on your machine, using your own local development environment and
.NET Core. You'll build a console application and see the basic object-oriented features that are part of the C#
language.
This tutorial assumes you've finished the online introductory tutorials, and you've installed .NET Core SDK and
Visual Studio Code.
Become familiar with the .NET development tools
3/12/2020 • 2 minutes to read • Edit Online
The first step in running a tutorial on your machine is to set up a development environment. The .NET tutorial
Hello World in 10 minutes has instructions for setting up your local development environment on Windows, Linux,
or macOS.
Alternatively, you can install the .NET Core SDK and Visual Studio Code.
Numbers in C#
In the Numbers in C# tutorial, you'll learn how computers store numbers and how to perform calculations with
different numeric types. You'll learn the basics of rounding and how to perform mathematical calculations using
C#.
This tutorial assumes that you have finished the Hello world lesson.
List collection
The List collection lesson gives you a tour of the List collection type that stores sequences of data. You'll learn how
to add and remove items, search for items, and sort the lists. You'll explore different kinds of lists.
This tutorial assumes that you have finished the lessons listed above.
Introduction to classes
This final introduction to C# tutorial is only available to run on your machine, using your own local development
environment and .NET Core. You'll build a console application and see the basic object-oriented features that are
part of the C# language.
Manipulate integral and floating point numbers in
C#
5/5/2020 • 9 minutes to read • Edit Online
This tutorial teaches you about the numeric types in C# interactively. You'll write small amounts of code, then
you'll compile and run that code. The tutorial contains a series of lessons that explore numbers and math
operations in C#. These lessons teach you the fundamentals of the C# language.
This tutorial expects you to have a machine you can use for development. The .NET tutorial Hello World in 10
minutes has instructions for setting up your local development environment on Windows, Linux, or macOS. A
quick overview of the commands you'll use is in the Become familiar with the development tools with links to
more details.
Open Program.cs in your favorite editor, and replace the line Console.WriteLine("Hello World!"); with the
following code:
int a = 18;
int b = 6;
int c = a + b;
Console.WriteLine(c);
// multiplication
c = a * b;
Console.WriteLine(c);
// division
c = a / b;
Console.WriteLine(c);
TIP
As you explore C# (or any programming language), you'll make mistakes when you write code. The compiler will find those
errors and report them to you. When the output contains error messages, look closely at the example code and the code in
your window to see what to fix. That exercise will help you learn the structure of C# code.
You've finished the first step. Before you start the next section, let's move the current code into a separate method.
That makes it easier to start working with a new example. Rename your Main method to WorkingWithIntegers
and write a new Main method that calls WorkingWithIntegers . When you finish, your code should look like this:
using System;
namespace NumbersInCSharp
{
class Program
{
static void WorkingWithIntegers()
{
int a = 18;
int b = 6;
// addition
int c = a + b;
Console.WriteLine(c);
// subtraction
c = a - b;
Console.WriteLine(c);
// multiplication
c = a * b;
Console.WriteLine(c);
// division
c = a / b;
Console.WriteLine(c);
}
//WorkingWithIntegers();
The // starts a comment in C#. Comments are any text you want to keep in your source code but not execute as
code. The compiler doesn't generate any executable code from comments.
The C# language defines the precedence of different mathematics operations with rules consistent with the rules
you learned in mathematics. Multiplication and division take precedence over addition and subtraction. Explore
that by adding the following code to your Main method, and executing dotnet run :
int a = 5;
int b = 4;
int c = 2;
int d = a + b * c;
Console.WriteLine(d);
The output demonstrates that the multiplication is performed before the addition.
You can force a different order of operation by adding parentheses around the operation or operations you want
performed first. Add the following lines and run again:
d = (a + b) * c;
Console.WriteLine(d);
Explore more by combining many different operations. Add something like the following lines at the bottom of
your Main method. Try dotnet run again.
d = (a + b) - 6 * c + (12 * 4) / 3 + 12;
Console.WriteLine(d);
You may have noticed an interesting behavior for integers. Integer division always produces an integer result,
even when you'd expect the result to include a decimal or fractional portion.
If you haven't seen this behavior, try the following code at the end of your Main method:
int e = 7;
int f = 4;
int g = 3;
int h = (e + f) / g;
Console.WriteLine(h);
namespace NumbersInCSharp
{
class Program
{
static void WorkingWithIntegers()
{
int a = 18;
int b = 6;
// addition
int c = a + b;
Console.WriteLine(c);
// subtraction
c = a - b;
Console.WriteLine(c);
// multiplication
c = a * b;
Console.WriteLine(c);
// division
c = a / b;
Console.WriteLine(c);
}
d = (a + b) * c;
Console.WriteLine(d);
d = (a + b) - 6 * c + (12 * 4) / 3 + 12;
Console.WriteLine(d);
int e = 7;
int f = 4;
int g = 3;
int h = (e + f) / g;
Console.WriteLine(h);
}
OrderPrecedence();
}
}
}
The C# integer type differs from mathematical integers in one other way: the int type has minimum and
maximum limits. Add this code to your Main method to see those limits:
If a calculation produces a value that exceeds those limits, you have an underflow or overflow condition. The
answer appears to wrap from one limit to the other. Add these two lines to your Main method to see an example:
Notice that the answer is very close to the minimum (negative) integer. It's the same as min + 2 . The addition
operation overflowed the allowed values for integers. The answer is a very large negative number because an
overflow "wraps around" from the largest possible integer value to the smallest.
There are other numeric types with different limits and precision that you would use when the int type doesn't
meet your needs. Let's explore those other types next.
Once again, let's move the code you wrote in this section into a separate method. Name it TestLimits .
double a = 5;
double b = 4;
double c = 2;
double d = (a + b) / c;
Console.WriteLine(d);
Notice that the answer includes the decimal portion of the quotient. Try a slightly more complicated expression
with doubles:
double e = 19;
double f = 23;
double g = 8;
double h = (e + f) / g;
Console.WriteLine(h);
The range of a double value is much greater than integer values. Try the following code below what you've written
so far:
These values are printed out in scientific notation. The number to the left of the E is the significand. The number
to the right is the exponent, as a power of 10.
Just like decimal numbers in math, doubles in C# can have rounding errors. Try this code:
You know that 0.3 repeating isn't exactly the same as 1/3 .
Challenge
Try other calculations with large numbers, small numbers, multiplication, and division using the double type. Try
more complicated calculations.
After you've spent some time with the challenge, take the code you've written and place it in a new method. Name
that new method WorkWithDoubles .
Notice that the range is smaller than the double type. You can see the greater precision with the decimal type by
trying the following code:
double a = 1.0;
double b = 3.0;
Console.WriteLine(a / b);
decimal c = 1.0M;
decimal d = 3.0M;
Console.WriteLine(c / d);
The M suffix on the numbers is how you indicate that a constant should use the decimal type. Otherwise, the
compiler assumes the double type.
NOTE
The letter M was chosen as the most visually distinct letter between the double and decimal keywords.
Notice that the math using the decimal type has more digits to the right of the decimal point.
Challenge
Now that you've seen the different numeric types, write code that calculates the area of a circle whose radius is
2.50 centimeters. Remember that the area of a circle is the radius squared multiplied by PI. One hint: .NET contains
a constant for PI, Math.PI that you can use for that value. Math.PI, like all constants declared in the System.Math
namespace, is a double value. For that reason, you should use double instead of decimal values for this
challenge.
You should get an answer between 19 and 20. You can check your answer by looking at the finished sample code
on GitHub.
Try some other formulas if you'd like.
You've completed the "Numbers in C#" quickstart. You can continue with the Branches and loops quickstart in
your own development environment.
You can learn more about numbers in C# in the following articles:
Integral numeric types
Floating-point numeric types
Built-in numeric conversions
Learn conditional logic with branch and loop
statements
5/14/2020 • 9 minutes to read • Edit Online
This tutorial teaches you how to write code that examines variables and changes the execution path based on
those variables. You write C# code and see the results of compiling and running it. The tutorial contains a series of
lessons that explore branching and looping constructs in C#. These lessons teach you the fundamentals of the C#
language.
This tutorial expects you to have a machine you can use for development. The .NET tutorial Hello World in 10
minutes has instructions for setting up your local development environment on Windows, Linux, or macOS. A
quick overview of the commands you'll use is in the Become familiar with the development tools with links to
more details.
This command creates a new .NET Core console application in the current directory.
Open Program.cs in your favorite editor, and replace the line Console.WriteLine("Hello World!"); with the
following code:
int a = 5;
int b = 6;
if (a + b > 10)
Console.WriteLine("The answer is greater than 10.");
Try this code by typing dotnet run in your console window. You should see the message "The answer is greater
than 10." printed to your console.
Modify the declaration of b so that the sum is less than 10:
int b = 3;
Type dotnet run again. Because the answer is less than 10, nothing is printed. The condition you're testing is
false. You don't have any code to execute because you've only written one of the possible branches for an if
statement: the true branch.
TIP
As you explore C# (or any programming language), you'll make mistakes when you write code. The compiler will find and
report the errors. Look closely at the error output and the code that generated the error. The compiler error can usually
help you find the problem.
This first sample shows the power of if and Boolean types. A Boolean is a variable that can have one of two
values: true or false . C# defines a special type, bool for Boolean variables. The if statement checks the value
of a bool . When the value is true , the statement following the if executes. Otherwise, it's skipped.
This process of checking conditions and executing statements based on those conditions is powerful.
int a = 5;
int b = 3;
if (a + b > 10)
Console.WriteLine("The answer is greater than 10");
else
Console.WriteLine("The answer is not greater than 10");
The statement following the else keyword executes only when the condition being tested is false . Combining
if and else with Boolean conditions provides all the power you need to handle both a true and a false
condition.
IMPORTANT
The indentation under the if and else statements is for human readers. The C# language doesn't treat indentation or
white space as significant. The statement following the if or else keyword will be executed based on the condition. All
the samples in this tutorial follow a common practice to indent lines based on the control flow of statements.
Because indentation isn't significant, you need to use { and } to indicate when you want more than one
statement to be part of the block that executes conditionally. C# programmers typically use those braces on all
if and else clauses. The following example is the same as the one you created. Modify your code above to
match the following code:
int a = 5;
int b = 3;
if (a + b > 10)
{
Console.WriteLine("The answer is greater than 10");
}
else
{
Console.WriteLine("The answer is not greater than 10");
}
TIP
Through the rest of this tutorial, the code samples all include the braces, following accepted practices.
You can test more complicated conditions. Add the following code in your Main method after the code you've
written so far:
int c = 4;
if ((a + b + c > 10) && (a == b))
{
Console.WriteLine("The answer is greater than 10");
Console.WriteLine("And the first number is equal to the second");
}
else
{
Console.WriteLine("The answer is not greater than 10");
Console.WriteLine("Or the first number is not equal to the second");
}
The == symbol tests for equality. Using == distinguishes the test for equality from assignment, which you saw in
a = 5 .
The && represents "and". It means both conditions must be true to execute the statement in the true branch.
These examples also show that you can have multiple statements in each conditional branch, provided you
enclose them in { and } .
You can also use || to represent "or". Add the following code after what you've written so far:
Modify the values of a , b , and c and switch between && and || to explore. You'll gain more understanding
of how the && and || operators work.
You've finished the first step. Before you start the next section, let's move the current code into a separate method.
That makes it easier to start working with a new example. Rename your Main method to ExploreIf and write a
new Main method that calls ExploreIf . When you've finished, your code should look like this:
using System;
namespace BranchesAndLoops
{
class Program
{
static void ExploreIf()
{
int a = 5;
int b = 3;
if (a + b > 10)
{
Console.WriteLine("The answer is greater than 10");
}
else
{
Console.WriteLine("The answer is not greater than 10");
}
int c = 4;
if ((a + b + c > 10) && (a > b))
{
Console.WriteLine("The answer is greater than 10");
Console.WriteLine("And the first number is greater than the second");
}
else
{
Console.WriteLine("The answer is not greater than 10");
Console.WriteLine("Or the first number is not greater than the second");
}
Comment out the call to ExploreIf() . It will make the output less cluttered as you work in this section:
//ExploreIf();
The // starts a comment in C#. Comments are any text you want to keep in your source code but not execute as
code. The compiler doesn't generate any executable code from comments.
The while statement checks a condition and executes the statement or statement block following the while . It
repeatedly checks the condition and executing those statements until the condition is false.
There's one other new operator in this example. The ++ after the counter variable is the increment operator. It
adds 1 to the value of counter and stores that value in the counter variable.
IMPORTANT
Make sure that the while loop condition changes to false as you execute the code. Otherwise, you create an infinite
loop where your program never ends. That is not demonstrated in this sample, because you have to force your program to
quit using CTRL-C or other means.
The while loop tests the condition before executing the code following the while . The do ... while loop
executes the code first, and then checks the condition. The do while loop is shown in the following code:
int counter = 0;
do
{
Console.WriteLine($"Hello World! The counter is {counter}");
counter++;
} while (counter < 10);
This do loop and the earlier while loop produce the same output.
The previous code does the same work as the while loop and the do loop you've already used. The for
statement has three parts that control how it works.
The first part is the for initializer : int index = 0; declares that index is the loop variable, and sets its initial
value to 0 .
The middle part is the for condition : index < 10 declares that this for loop continues to execute as long as the
value of counter is less than 10.
The final part is the for iterator : index++ specifies how to modify the loop variable after executing the block
following the for statement. Here, it specifies that index should be incremented by 1 each time the block
executes.
Experiment yourself. Try each of the following variations:
Change the initializer to start at a different value.
Change the condition to stop at a different value.
When you're done, let's move on to write some code yourself to use what you've learned.
There's one other looping statement that isn't covered in this tutorial: the foreach statement. The foreach
statement repeats its statement for every item in a sequence of items. It's most often used with collections, so it's
covered in the next tutorial.
You can nest one loop inside the other to form pairs:
You can see that the outer loop increments once for each full run of the inner loop. Reverse the row and column
nesting, and see the changes for yourself.
Try it yourself. Then check how you did. You should get 63 for an answer. You can see one possible answer by
viewing the completed code on GitHub.
You've completed the "branches and loops" tutorial.
You can continue with the Arrays and collections tutorial in your own development environment.
You can learn more about these concepts in these articles:
If and else statement
While statement
Do statement
For statement
Learn to manage data collections using the generic
list type
9/3/2020 • 5 minutes to read • Edit Online
This introductory tutorial provides an introduction to the C# language and the basics of the List<T> class.
This tutorial expects you to have a machine you can use for development. The .NET tutorial Hello World in 10
minutes has instructions for setting up your local development environment on Windows, Linux, or macOS. A
quick overview of the commands you'll use is in Become familiar with the development tools, with links to more
details.
using System;
using System.Collections.Generic;
namespace list_tutorial
{
class Program
{
static void Main(string[] args)
{
var names = new List<string> { "<name>", "Ana", "Felipe" };
foreach (var name in names)
{
Console.WriteLine($"Hello {name.ToUpper()}!");
}
}
}
}
Replace <name> with your name. Save Program.cs. Type dotnet run in your console window to try it.
You've created a list of strings, added three names to that list, and printed out the names in all CAPS. You're using
concepts that you've learned in earlier tutorials to loop through the list.
The code to display names makes use of the string interpolation feature. When you precede a string with the $
character, you can embed C# code in the string declaration. The actual string replaces that C# code with the value
it generates. In this example, it replaces the {name.ToUpper()} with each name, converted to capital letters,
because you called the ToUpper method.
Let's keep exploring.
You've added two more names to the end of the list. You've also removed one as well. Save the file, and type
dotnet run to try it.
The List<T> enables you to reference individual items by index as well. You place the index between [ and ]
tokens following the list name. C# uses 0 for the first index. Add this code directly below the code you just added
and try it:
You can't access an index beyond the end of the list. Remember that indices start at 0, so the largest valid index is
one less than the number of items in the list. You can check how long the list is using the Count property. Add the
following code at the end of the Main method:
Save the file, and type dotnet run again to see the results.
The items in your list can be sorted as well. The Sort method sorts all the items in the list in their normal order
(alphabetically for strings). Add this code to the bottom of our Main method:
names.Sort();
foreach (var name in names)
{
Console.WriteLine($"Hello {name.ToUpper()}!");
}
Save the file and type dotnet run to try this latest version.
Before you start the next section, let's move the current code into a separate method. That makes it easier to start
working with a new example. Rename your Main method to WorkingWithStrings and write a new Main method
that calls WorkingWithStrings . When you've finished, your code should look like this:
using System;
using System.Collections.Generic;
namespace list_tutorial
{
class Program
{
static void Main(string[] args)
{
WorkingWithStrings();
}
Console.WriteLine();
names.Add("Maria");
names.Add("Bill");
names.Remove("Ana");
foreach (var name in names)
{
Console.WriteLine($"Hello {name.ToUpper()}!");
}
names.Sort();
foreach (var name in names)
{
Console.WriteLine($"Hello {name.ToUpper()}!");
}
}
}
}
That creates a list of integers, and sets the first two integers to the value 1. These are the first two values of a
Fibonacci Sequence, a sequence of numbers. Each next Fibonacci number is found by taking the sum of the
previous two numbers. Add this code:
fibonacciNumbers.Add(previous + previous2);
Save the file and type dotnet run to see the results.
TIP
To concentrate on just this section, you can comment out the code that calls WorkingWithStrings(); . Just put two /
characters in front of the call like this: // WorkingWithStrings(); .
Challenge
See if you can put together some of the concepts from this and earlier lessons. Expand on what you've built so far
with Fibonacci Numbers. Try to write the code to generate the first 20 numbers in the sequence. (As a hint, the
20th Fibonacci number is 6765.)
Complete challenge
You can see an example solution by looking at the finished sample code on GitHub.
With each iteration of the loop, you're taking the last two integers in the list, summing them, and adding that value
to the list. The loop repeats until you've added 20 items to the list.
Congratulations, you've completed the list tutorial. You can continue with the Introduction to classes tutorial in
your own development environment.
You can learn more about working with the List type in the .NET fundamentals article on collections. You'll also
learn about many other collection types.
Explore object oriented programming with classes
and objects
5/14/2020 • 9 minutes to read • Edit Online
This tutorial expects that you have a machine you can use for development. The .NET tutorial Hello World in 10
minutes has instructions for setting up your local development environment on Windows, Linux, or macOS. A
quick overview of the commands you'll use is in the Become familiar with the development tools with links to
more details.
using System;
namespace classes
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}
In this tutorial, you're going to create new types that represent a bank account. Typically developers define each
class in a different text file. That makes it easier to manage as a program grows in size. Create a new file named
BankAccount.cs in the classes directory.
This file will contain the definition of a bank account . Object Oriented programming organizes code by creating
types in the form of classes . These classes contain the code that represents a specific entity. The BankAccount class
represents a bank account. The code implements specific operations through methods and properties. In this
tutorial, the bank account supports this behavior:
1. It has a 10-digit number that uniquely identifies the bank account.
2. It has a string that stores the name or names of the owners.
3. The balance can be retrieved.
4. It accepts deposits.
5. It accepts withdrawals.
6. The initial balance must be positive.
7. Withdrawals cannot result in a negative balance.
namespace classes
{
public class BankAccount
{
public string Number { get; }
public string Owner { get; set; }
public decimal Balance { get; }
Before going on, let's take a look at what you've built. The namespace declaration provides a way to logically
organize your code. This tutorial is relatively small, so you'll put all the code in one namespace.
public class BankAccount defines the class, or type, you are creating. Everything inside the { and } that follows
the class declaration defines the state and behavior of the class. There are five members of the BankAccount class.
The first three are proper ties . Properties are data elements and can have code that enforces validation or other
rules. The last two are methods . Methods are blocks of code that perform a single function. Reading the names of
each of the members should provide enough information for you or another developer to understand what the
class does.
Constructors are called when you create an object using new . Replace the line
Console.WriteLine("Hello World!"); in Program.cs with the following code (replace <name> with your name):
Let's run what you've built so far. If you're using Visual Studio, Select Star t without debugging from the Run
menu. If you're using a command line, type dotnet run in the directory where you've created your project.
Did you notice that the account number is blank? It's time to fix that. The account number should be assigned
when the object is constructed. But it shouldn't be the responsibility of the caller to create it. The BankAccount class
code should know how to assign new account numbers. A simple way to do this is to start with a 10-digit number.
Increment it when each new account is created. Finally, store the current account number when an object is
constructed.
Add a member declaration to the BankAccount class. Place the following line of code after the opening brace { at
the beginning of the BankAccount class:
This is a data member. It's private , which means it can only be accessed by code inside the BankAccount class. It's
a way of separating the public responsibilities (like having an account number) from the private implementation
(how account numbers are generated). It is also static , which means it is shared by all of the BankAccount
objects. The value of a non-static variable is unique to each instance of the BankAccount object. Add the following
two lines to the constructor to assign the account number. Place them after the line that says
this.Balance = initialBalance :
this.Number = accountNumberSeed.ToString();
accountNumberSeed++;
using System;
namespace classes
{
public class Transaction
{
public decimal Amount { get; }
public DateTime Date { get; }
public string Notes { get; }
Now, let's add a List<T> of Transaction objects to the BankAccount class. Add the following declaration after the
constructor in your BankAccount.cs file:
using System.Collections.Generic;
Now, let's change how the Balance is reported. It can be found by summing the values of all transactions. Modify
the declaration of Balance in the BankAccount class to the following:
return balance;
}
}
This example shows an important aspect of proper ties . You're now computing the balance when another
programmer asks for the value. Your computation enumerates all transactions, and provides the sum as the
current balance.
Next, implement the MakeDeposit and MakeWithdrawal methods. These methods will enforce the final two rules:
that the initial balance must be positive, and that any withdrawal must not create a negative balance.
This introduces the concept of exceptions . The standard way of indicating that a method cannot complete its
work successfully is to throw an exception. The type of exception and the message associated with it describe the
error. Here, the MakeDeposit method throws an exception if the amount of the deposit is negative. The
MakeWithdrawal method throws an exception if the withdrawal amount is negative, or if applying the withdrawal
results in a negative balance. Add the following code after the declaration of the allTransactions list:
this.Owner = name;
MakeDeposit(initialBalance, DateTime.Now, "Initial balance");
}
DateTime.Now is a property that returns the current date and time. Test this by adding a few deposits and
withdrawals in your Main method, following the code that creates a new BankAccount :
Next, test that you are catching error conditions by trying to create an account with a negative balance. Add the
following code after the preceding code you just added:
You use the try and catch statements to mark a block of code that may throw exceptions and to catch those
errors that you expect. You can use the same technique to test the code that throws an exception for a negative
balance. Add the following code at the end of your Main method:
decimal balance = 0;
report.AppendLine("Date\t\tAmount\tBalance\tNote");
foreach (var item in allTransactions)
{
balance += item.Amount;
report.AppendLine($"{item.Date.ToShortDateString()}\t{item.Amount}\t{balance}\t{item.Notes}");
}
return report.ToString();
}
This uses the StringBuilder class to format a string that contains one line for each transaction. You've seen the
string formatting code earlier in these tutorials. One new character is \t . That inserts a tab to format the output.
Add this line to test it in Program.cs:
Console.WriteLine(account.GetAccountHistory());
Next steps
If you got stuck, you can see the source for this tutorial in our GitHub repo.
Congratulations, you've finished all our introduction to C# tutorials. If you're eager to learn more, try more of our
tutorials.
Use string interpolation to construct formatted strings
5/5/2020 • 7 minutes to read • Edit Online
This tutorial teaches you how to use C# string interpolation to insert values into a single result string. You write C#
code and see the results of compiling and running it. The tutorial contains a series of lessons that show you how to
insert values into a string and format those values in different ways.
This tutorial expects that you have a machine you can use for development. The .NET tutorial Hello World in 10
minutes has instructions for setting up your local development environment on Windows, Linux, or macOS. You
can also complete the interactive version of this tutorial in your browser.
This command creates a new .NET Core console application in the current directory.
Open Program.cs in your favorite editor, and replace the line Console.WriteLine("Hello World!"); with the
following code, where you replace <name> with your name:
Try this code by typing dotnet run in your console window. When you run the program, it displays a single string
that includes your name in the greeting. The string included in the WriteLine method call is an interpolated string
expression. It's a kind of template that lets you construct a single string (called the result string) from a string that
includes embedded code. Interpolated strings are particularly useful for inserting values into a string or
concatenating ( joining together) strings.
This simple example contains the two elements that every interpolated string must have:
A string literal that begins with the $ character before its opening quotation mark character. There can't be
any spaces between the $ symbol and the quotation mark character. (If you'd like to see what happens if
you include one, insert a space after the $ character, save the file, and run the program again by typing
dotnet run in the console window. The C# compiler displays an error message, "error CS1056: Unexpected
character '$'".)
One or more interpolation expressions. An interpolation expression is indicated by an opening and closing
brace ( { and } ). You can put any C# expression that returns a value (including null ) inside the braces.
Let's try a few more string interpolation examples with some other data types.
Then we create an instance of the Vegetable class named item by using the new operator and providing a name
for the constructor Vegetable :
Finally, we include the item variable into an interpolated string that also contains a DateTime value, a Decimal
value, and a Unit enumeration value. Replace all of the C# code in your editor with the following code, and then
use the dotnet run command to run it:
using System;
Note that the interpolation expression item in the interpolated string resolves to the text "eggplant" in the result
string. That's because, when the type of the expression result is not a string, the result is resolved to a string in the
following way:
If the interpolation expression evaluates to null , an empty string ("", or String.Empty) is used.
If the interpolation expression doesn't evaluate to null , typically the ToString method of the result type is
called. You can test this by updating the implementation of the Vegetable.ToString method. You might not
even need to implement the ToString method since every type has some implementation of this method.
To test this, comment out the definition of the Vegetable.ToString method in the example (to do that, put a
comment symbol, // , in front of it). In the output, the string "eggplant" is replaced by the fully qualified
type name ("Vegetable" in this example), which is the default behavior of the Object.ToString() method. The
default behavior of the ToString method for an enumeration value is to return the string representation of
the value.
In the output from this example, the date is too precise (the price of eggplant doesn't change every second), and
the price value doesn't indicate a unit of currency. In the next section, you'll learn how to fix those issues by
controlling the format of string representations of the expression results.
You specify a format string by following the interpolation expression with a colon (":") and the format string. "d" is a
standard date and time format string that represents the short date format. "C2" is a standard numeric format
string that represents a number as a currency value with two digits after the decimal point.
A number of types in the .NET libraries support a predefined set of format strings. These include all the numeric
types and the date and time types. For a complete list of types that support format strings, see Format Strings and
.NET Class Library Types in the Formatting Types in .NET article.
Try modifying the format strings in your text editor and, each time you make a change, rerun the program to see
how the changes affect the formatting of the date and time and the numeric value. Change the "d" in {date:d} to
"t" (to display the short time format), "y" (to display the year and month), and "yyyy" (to display the year as a four-
digit number). Change the "C2" in {price:C2} to "e" (for exponential notation) and "F3" (for a numeric value with
three digits after the decimal point).
In addition to controlling formatting, you can also control the field width and alignment of the formatted strings
that are included in the result string. In the next section, you'll learn how to do this.
The names of authors are left-aligned, and the titles they wrote are right-aligned. You specify the alignment by
adding a comma (",") after an interpolation expression and designating the minimum field width. If the specified
value is a positive number, the field is right-aligned. If it is a negative number, the field is left-aligned.
Try removing the negative signs from the {"Author",-25} and {title.Key,-25} code and run the example again,
as the following code does:
Console.WriteLine($"|{"Author",25}|{"Title",30}|");
foreach (var title in titles)
Console.WriteLine($"|{title.Key,25}|{title.Value,30}|");
This tutorial shows you how to use string interpolation to format and include expression results in a result string.
The examples assume that you are familiar with basic C# concepts and .NET type formatting. If you are new to
string interpolation or .NET type formatting, check out the interactive string interpolation tutorial first. For more
information about formatting types in .NET, see the Formatting Types in .NET topic.
NOTE
The C# examples in this article run in the Try.NET inline code runner and playground. Select the Run button to run an
example in an interactive window. Once you execute the code, you can modify it and run the modified code by selecting Run
again. The modified code either runs in the interactive window or, if compilation fails, the interactive window displays all C#
compiler error messages.
Introduction
The string interpolation feature is built on top of the composite formatting feature and provides a more readable
and convenient syntax to include formatted expression results in a result string.
To identify a string literal as an interpolated string, prepend it with the $ symbol. You can embed any valid C#
expression that returns a value in an interpolated string. In the following example, as soon as an expression is
evaluated, its result is converted into a string and included in a result string:
double a = 3;
double b = 4;
Console.WriteLine($"Area of the right triangle with legs of {a} and {b} is {0.5 * a * b}");
Console.WriteLine($"Length of the hypotenuse of the right triangle with legs of {a} and {b} is
{CalculateHypotenuse(a, b)}");
double CalculateHypotenuse(double leg1, double leg2) => Math.Sqrt(leg1 * leg1 + leg2 * leg2);
// Expected output:
// Area of the right triangle with legs of 3 and 4 is 6
// Length of the hypotenuse of the right triangle with legs of 3 and 4 is 5
As the example shows, you include an expression in an interpolated string by enclosing it with braces:
{<interpolationExpression>}
Interpolated strings support all the capabilities of the string composite formatting feature. That makes them a
more readable alternative to the use of the String.Format method.
{<interpolationExpression>:<formatString>}
The following example shows how to specify standard and custom format strings for expressions that produce
date and time or numeric results:
// Expected output:
// On Sunday, November 25, 1731 Leonhard Euler introduced the letter e to denote 2.71828 in a letter to
Christian Goldbach.
For more information, see the Format String Component section of the Composite Formatting topic. That section
provides links to the topics that describe standard and custom format strings supported by .NET base types.
{<interpolationExpression>,<alignment>}
If the alignment value is positive, the formatted expression result is right-aligned; if negative, it's left-aligned.
If you need to specify both alignment and a format string, start with the alignment component:
{<interpolationExpression>,<alignment>:<formatString>}
The following example shows how to specify alignment and uses pipe characters ("|") to delimit text fields:
double a = 3;
double b = 4;
Console.WriteLine($"Three classical Pythagorean means of {a} and {b}:");
Console.WriteLine($"|{"Arithmetic",NameAlignment}|{0.5 * (a + b),ValueAlignment:F3}|");
Console.WriteLine($"|{"Geometric",NameAlignment}|{Math.Sqrt(a * b),ValueAlignment:F3}|");
Console.WriteLine($"|{"Harmonic",NameAlignment}|{2 / (1 / a + 1 / b),ValueAlignment:F3}|");
// Expected output:
// Three classical Pythagorean means of 3 and 4:
// |Arithmetic| 3.500|
// |Geometric| 3.464|
// |Harmonic | 3.429|
As the example output shows, if the length of the formatted expression result exceeds specified field width, the
alignment value is ignored.
For more information, see the Alignment Component section of the Composite Formatting topic.
// Expected output:
// Find the intersection of the {1, 2, 7, 9} and {7, 9, 12} sets.
// C:\Users\Jane\Documents
// C:\Users\Jane\Documents
As the example shows, you can use one FormattableString instance to generate multiple result strings for various
cultures.
Conclusion
This tutorial describes common scenarios of string interpolation usage. For more information about string
interpolation, see the String interpolation topic. For more information about formatting types in .NET, see the
Formatting Types in .NET and Composite formatting topics.
See also
String.Format
System.FormattableString
System.IFormattable
Strings
Tutorial: Update interfaces with default interface
methods in C# 8.0
9/3/2020 • 6 minutes to read • Edit Online
Beginning with C# 8.0 on .NET Core 3.0, you can define an implementation when you declare a member of an
interface. The most common scenario is to safely add members to an interface already released and used by
innumerable clients.
In this tutorial, you'll learn how to:
Extend interfaces safely by adding methods with implementations.
Create parameterized implementations to provide greater flexibility.
Enable implementers to provide a more specific implementation in the form of an override.
Prerequisites
You’ll need to set up your machine to run .NET Core, including the C# 8.0 compiler. The C# 8.0 compiler is available
starting with Visual Studio 2019 version 16.3 or the .NET Core 3.0 SDK.
Scenario overview
This tutorial starts with version 1 of a customer relationship library. You can get the starter application on our
samples repo on GitHub. The company that built this library intended customers with existing applications to adopt
their library. They provided minimal interface definitions for users of their library to implement. Here's the interface
definition for a customer:
From those interfaces, the team could build a library for their users to create a better experience for their
customers. Their goal was to create a deeper relationship with existing customers and improve their relationships
with new customers.
Now, it's time to upgrade the library for the next release. One of the requested features enables a loyalty discount
for customers that have lots of orders. This new loyalty discount gets applied whenever a customer makes an
order. The specific discount is a property of each individual customer. Each implementation of ICustomer can set
different rules for the loyalty discount.
The most natural way to add this functionality is to enhance the ICustomer interface with a method to apply any
loyalty discount. This design suggestion caused concern among experienced developers: "Interfaces are immutable
once they've been released! This is a breaking change!" C# 8.0 adds default interface implementations for
upgrading interfaces. The library authors can add new members to the interface and provide a default
implementation for those members.
Default interface implementations enable developers to upgrade an interface while still enabling any implementors
to override that implementation. Users of the library can accept the default implementation as a non-breaking
change. If their business rules are different, they can override.
// Version 1:
public decimal ComputeLoyaltyDiscount()
{
DateTime TwoYearsAgo = DateTime.Now.AddYears(-2);
if ((DateJoined < TwoYearsAgo) && (PreviousOrders.Count() > 10))
{
return 0.10m;
}
return 0;
}
That cast from SampleCustomer to ICustomer is necessary. The SampleCustomer class doesn't need to provide an
implementation for ComputeLoyaltyDiscount ; that's provided by the ICustomer interface. However, the
SampleCustomer class doesn't inherit members from its interfaces. That rule hasn't changed. In order to call any
method declared and implemented in the interface, the variable must be the type of the interface, ICustomer in this
example.
Provide parameterization
That's a good start. But, the default implementation is too restrictive. Many consumers of this system may choose
different thresholds for number of purchases, a different length of membership, or a different percentage discount.
You can provide a better upgrade experience for more customers by providing a way to set those parameters. Let's
add a static method that sets those three parameters controlling the default implementation:
// Version 2:
public static void SetLoyaltyThresholds(
TimeSpan ago,
int minimumOrders = 10,
decimal percentageDiscount = 0.10m)
{
length = ago;
orderCount = minimumOrders;
discountPercent = percentageDiscount;
}
private static TimeSpan length = new TimeSpan(365 * 2, 0,0,0); // two years
private static int orderCount = 10;
private static decimal discountPercent = 0.10m;
There are many new language capabilities shown in that small code fragment. Interfaces can now include static
members, including fields and methods. Different access modifiers are also enabled. The additional fields are
private, the new method is public. Any of the modifiers are allowed on interface members.
Applications that use the general formula for computing the loyalty discount, but different parameters, don't need
to provide a custom implementation; they can set the arguments through a static method. For example, the
following code sets a "customer appreciation" that rewards any customer with more than one month's
membership:
In an implementation of a class that implements this interface, the override can call the static helper method, and
extend that logic to provide the "new customer" discount:
You can see the entire finished code in our samples repo on GitHub. You can get the starter application on our
samples repo on GitHub.
These new features mean that interfaces can be updated safely when there's a reasonable default implementation
for those new members. Carefully design interfaces to express single functional ideas that can be implemented by
multiple classes. That makes it easier to upgrade those interface definitions when new requirements are discovered
for that same functional idea.
Tutorial: Mix functionality in when creating classes
using interfaces with default interface methods
5/14/2020 • 8 minutes to read • Edit Online
Beginning with C# 8.0 on .NET Core 3.0, you can define an implementation when you declare a member of an
interface. This feature provides new capabilities where you can define default implementations for features
declared in interfaces. Classes can pick when to override functionality, when to use the default functionality, and
when not to declare support for discrete features.
In this tutorial, you'll learn how to:
Create interfaces with implementations that describe discrete features.
Create classes that use the default implementations.
Create classes that override some or all of the default implementations.
Prerequisites
You’ll need to set up your machine to run .NET Core, including the C# 8.0 compiler. The C# 8.0 compiler is available
starting with Visual Studio 2019 version 16.3, or the .NET Core 3.0 SDK or later.
Create interfaces
Start by creating the interface that defines the behavior for all lights:
A basic overhead light fixture might implement this interface as shown in the following code:
public override string ToString() => $"The light is {(isOn ? "on" : "off")}";
}
In this tutorial, the code doesn't drive IoT devices, but emulates those activities by writing messages to the console.
You can explore the code without automating your house.
Next, let's define the interface for a light that can automatically turn off after a timeout:
You could add a basic implementation to the overhead light, but a better solution is to modify this interface
definition to provide a virtual default implementation:
A different light type may support a more sophisticated protocol. It can provide its own implementation for
TurnOnFor , as shown in the following code:
Unlike overriding virtual class methods, the declaration of TurnOnFor in the HalogenLight class does not use the
override keyword.
The default implementation enables any light to blink. The overhead light can add both timer and blink capabilities
using the default implementation:
public override string ToString() => $"The light is {(isOn ? "on" : "off")}";
}
A new light type, the LEDLight supports both the timer function and the blink function directly. This light style
implements both the ITimerLight and IBlinkingLight interfaces, and overrides the Blink method:
public override string ToString() => $"The light is {(isOn ? "on" : "off")}";
}
public override string ToString() => $"The light is {(isOn ? "on" : "off")}";
}
The HalogenLight you created earlier doesn't support blinking. So, don't add the IBlinkingLight to the list of its
supported interfaces.
The following code in your Main method creates each light type in sequence and tests that light:
These changes compile cleanly, even though the ExtraFancyLight declares support for the ILight interface and
both derived interfaces, ITimerLight and IBlinkingLight . There's only one "closest" implementation declared in
the ILight interface. Any class that declared an override would become the one "closest" implementation. You saw
examples in the preceding classes that overrode the members of other derived interfaces.
Avoid overriding the same method in multiple derived interfaces. Doing so creates an ambiguous method call
whenever a class implements both derived interfaces. The compiler can't pick a single better method so it issues an
error. For example, if both the IBlinkingLight and ITimerLight implemented an override of PowerStatus , the
OverheadLight would need to provide a more specific override. Otherwise, the compiler can't pick between the
implementations in the two derived interfaces. You can usually avoid this situation by keeping interface definitions
small and focused on one feature. In this scenario, each capability of a light is its own interface; multiple interfaces
are only inherited by classes.
This sample shows one scenario where you can define discrete features that can be mixed into classes. You declare
any set of supported functionality by declaring which interfaces a class supports. The use of virtual default interface
methods enables classes to use or define a different implementation for any or all the interface methods. This
language capability provides new ways to model the real-world systems you're building. Default interface methods
provide a clearer way to express related classes that may mix and match different features using virtual
implementations of those capabilities.
Indices and ranges
3/12/2020 • 5 minutes to read • Edit Online
Ranges and indices provide a succinct syntax for accessing single elements or ranges in a sequence.
In this tutorial, you'll learn how to:
Use the syntax for ranges in a sequence.
Understand the design decisions for the start and end of each sequence.
Learn scenarios for the Index and Range types.
You can retrieve the last word with the ^1 index. Add the following code below the initialization:
A range specifies the start and end of a range. Ranges are exclusive, meaning the end isn't included in the range.
The range [0..^0] represents the entire range, just as [0..sequence.Length] represents the entire range.
The following code creates a subrange with the words "quick", "brown", and "fox". It includes words[1] through
words[3] . The element words[4] isn't in the range. Add the following code to the same method. Copy and paste it
at the bottom of the interactive window.
string[] quickBrownFox = words[1..4];
foreach (var word in quickBrownFox)
Console.Write($"< {word} >");
Console.WriteLine();
The following code creates a subrange with "lazy" and "dog". It includes words[^2] and words[^1] . The end index
words[^0] isn't included. Add the following code as well:
The following examples create ranges that are open ended for the start, end, or both:
You can also declare ranges or indices as variables. The variable can then be used inside the [ and ] characters:
The following sample shows many of the reasons for those choices. Modify x , y , and z to try different
combinations. When you experiment, use values where x is less than y , and y is less than z for valid
combinations. Add the following code in a new method. Try different combinations:
int[] numbers = Enumerable.Range(0, 100).ToArray();
int x = 12;
int y = 25;
int z = 36;
(int min, int max, double average) MovingAverage(int[] subSequence, Range range) =>
(
subSequence[range].Min(),
subSequence[range].Max(),
subSequence[range].Average()
);
C# 8.0 introduces nullable reference types, which complement reference types the same way nullable value types
complement value types. You declare a variable to be a nullable reference type by appending a ? to the type.
For example, string? represents a nullable string . You can use these new types to more clearly express your
design intent: some variables must always have a value, others may be missing a value.
In this tutorial, you'll learn how to:
Incorporate nullable and non-nullable reference types into your designs
Enable nullable reference type checks throughout your code.
Write code where the compiler enforces those design decisions.
Use the nullable reference feature in your own designs
Prerequisites
You'll need to set up your machine to run .NET Core, including the C# 8.0 compiler. The C# 8.0 compiler is available
with Visual Studio 2019, or .NET Core 3.0.
This tutorial assumes you're familiar with C# and .NET, including either Visual Studio or the .NET Core CLI.
<Nullable>enable</Nullable>
namespace NullableIntroduction
{
public class SurveyQuestion
{
}
}
The compiler interprets every reference type variable declaration as a non-nullable reference type for code in an
enabled nullable annotation context. You can see your first warning by adding properties for the question text and
the type of question, as shown in the following code:
namespace NullableIntroduction
{
public enum QuestionType
{
YesNo,
Number,
Text
}
Because you haven't initialized QuestionText , the compiler issues a warning that a non-nullable property hasn't
been initialized. Your design requires the question text to be non-null, so you add a constructor to initialize it and
the QuestionType value as well. The finished class definition looks like the following code:
namespace NullableIntroduction
{
public enum QuestionType
{
YesNo,
Number,
Text
}
Adding the constructor removes the warning. The constructor argument is also a non-nullable reference type, so
the compiler doesn't issue any warnings.
Next, create a public class named SurveyRun . This class contains a list of SurveyQuestion objects and methods to
add questions to the survey, as shown in the following code:
using System.Collections.Generic;
namespace NullableIntroduction
{
public class SurveyRun
{
private List<SurveyQuestion> surveyQuestions = new List<SurveyQuestion>();
As before, you must initialize the list object to a non-null value or the compiler issues a warning. There are no null
checks in the second overload of AddQuestion because they aren't needed: You've declared that variable to be non-
nullable. Its value can't be null .
Switch to Program.cs in your editor and replace the contents of Main with the following lines of code:
Because the entire project is in an enabled nullable annotation context, you'll get warnings when you pass null to
any method expecting a non-nullable reference type. Try it by adding the following line to Main :
surveyRun.AddQuestion(QuestionType.Text, default);
namespace NullableIntroduction
{
public class SurveyResponse
{
public int Id { get; }
Next, add a static method to create new participants by generating a random ID:
The main responsibility of this class is to generate the responses for a participant to the questions in the survey.
This responsibility has a few steps:
1. Ask for participation in the survey. If the person doesn't consent, return a missing (or null) response.
2. Ask each question and record the answer. Each answer may also be missing (or null).
Add the following code to your SurveyResponse class:
private Dictionary<int, string>? surveyResponses;
public bool AnswerSurvey(IEnumerable<SurveyQuestion> questions)
{
if (ConsentToSurvey())
{
surveyResponses = new Dictionary<int, string>();
int index = 0;
foreach (var question in questions)
{
var answer = GenerateAnswer(question);
if (answer != null)
{
surveyResponses.Add(index, answer);
}
index++;
}
}
return surveyResponses != null;
}
The storage for the survey answers is a Dictionary<int, string>? , indicating that it may be null. You're using the
new language feature to declare your design intent, both to the compiler and to anyone reading your code later. If
you ever dereference surveyResponses without checking for the null value first, you'll get a compiler warning.
You don't get a warning in the AnswerSurvey method because the compiler can determine the surveyResponses
variable was set to a non-null value above.
Using null for missing answers highlights a key point for working with nullable reference types: your goal isn't to
remove all null values from your program. Rather, your goal is to ensure that the code you write expresses the
intent of your design. Missing values are a necessary concept to express in your code. The null value is a clear
way to express those missing values. Trying to remove all null values only leads to defining some other way to
express those missing values without null .
Next, you need to write the PerformSurvey method in the SurveyRun class. Add the following code in the
SurveyRun class:
private List<SurveyResponse>? respondents;
public void PerformSurvey(int numberOfRespondents)
{
int respondentsConsenting = 0;
respondents = new List<SurveyResponse>();
while (respondentsConsenting < numberOfRespondents)
{
var respondent = SurveyResponse.GetRandomId();
if (respondent.AnswerSurvey(surveyQuestions))
respondentsConsenting++;
respondents.Add(respondent);
}
}
Here again, your choice of a nullable List<SurveyResponse>? indicates the response may be null. That indicates the
survey hasn't been given to any respondents yet. Notice that respondents are added until enough have consented.
The last step to run the survey is to add a call to perform the survey at the end of the Main method:
surveyRun.PerformSurvey(50);
Because surveyResponsesis a nullable reference type, null checks are necessary before de-referencing it. The
Answer method returns a non-nullable string, so we have to cover the case of a missing answer by using the null-
coalescing operator.
Next, add these three expression-bodied members to the SurveyRun class:
The AllParticipants member must take into account that the respondents variable might be null, but the return
value can't be null. If you change that expression by removing the ?? and the empty sequence that follows, the
compiler warns you the method might return null and its return signature returns a non-nullable type.
Finally, add the following loop at the bottom of the Main method:
foreach (var participant in surveyRun.AllParticipants)
{
Console.WriteLine($"Participant: {participant.Id}:");
if (participant.AnsweredSurvey)
{
for (int i = 0; i < surveyRun.Questions.Count; i++)
{
var answer = participant.Answer(i);
Console.WriteLine($"\t{surveyRun.GetQuestion(i).QuestionText} : {answer}");
}
}
else
{
Console.WriteLine("\tNo responses");
}
}
You don't need any null checks in this code because you've designed the underlying interfaces so that they all
return non-nullable reference types.
Next steps
Learn more by migrating an existing application to use nullable reference types:
Upgrade an application to use nullable reference types
Tutorial: Migrate existing code with nullable reference
types
3/12/2020 • 13 minutes to read • Edit Online
C# 8 introduces nullable reference types , which complement reference types the same way nullable value types
complement value types. You declare a variable to be a nullable reference type by appending a ? to the type.
For example, string? represents a nullable string . You can use these new types to more clearly express your
design intent: some variables must always have a value, others may be missing a value. Any existing variables of a
reference type would be interpreted as a non-nullable reference type.
In this tutorial, you'll learn how to:
Enable null reference checks as you work with code.
Diagnose and correct different warnings related to null values.
Manage the interface between nullable enabled and nullable disabled contexts.
Control nullable annotation contexts.
Prerequisites
You’ll need to set up your machine to run .NET Core, including the C# 8.0 compiler. The C# 8 compiler is available
starting with Visual Studio 2019 version 16.3 or .NET Core 3.0 SDK.
This tutorial assumes you're familiar with C# and .NET, including either Visual Studio or the .NET Core CLI.
<LangVersion>8.0</LangVersion>
Upgrading the language version selects C# 8.0, but does not enable the nullable annotation context or the nullable
warning context. Rebuild the project to ensure that it builds without warnings.
A good next step is to turn on the nullable annotation context and see how many warnings are generated. Add the
following element to both csproj files in the solution, directly under the LangVersion element:
<Nullable>enable</Nullable>
Do a test build, and notice the warning list. In this small application, the compiler generates five warnings, so it's
likely you'd leave the nullable annotation context enabled and start fixing warnings for the entire project.
That strategy works only for smaller projects. For any larger projects, the number of warnings generated by
enabling the nullable annotation context for the entire codebase makes it harder to fix the warnings systematically.
For larger enterprise projects, you'll often want to migrate one project at a time. In each project, migrate one class
or file at a time.
#nullable enable
public class NewsStoryViewModel
{
public DateTimeOffset Published { get; set; }
public string Title { get; set; }
public string Uri { get; set; }
}
#nullable restore
These two directives help you focus your migration efforts. The nullable warnings are generated for the area of
code you're actively working on. You'll leave them on until you're ready to turn on the warnings for the entire
project. You should use the restore rather than disable value so that you don't accidentally disable the context
later when you've turned on nullable annotations for the entire project. Once you've turned on the nullable
annotation context for the entire project, you can remove all the #nullable pragmas from that project.
The NewsStoryViewModel class is a data transfer object (DTO) and two of the properties are read/write strings:
These two properties cause CS8618 , "Non-nullable property is uninitialized". That's clear enough: both string
properties have the default value of null when a NewsStoryViewModel is constructed. What's important to
discover is how NewsStoryViewModel objects are constructed. Looking at this class, you can't tell if the null value
is part of the design, or if these objects are set to non-null values whenever one is created. The news stories are
created in the GetNews method of the NewsService class:
The assignment of Title and Uri to default which is null for the string type doesn't change the runtime
behavior of the program. The NewsStoryViewModel is still constructed with null values, but now the compiler
reports no warnings. The null-forgiving operator , the ! character following the default expression tells the
compiler that the preceding expression is not null. This technique may be expedient when other changes force
much larger changes to a code base, but in this application there is a relatively quick and better solution: Make the
NewsStoryViewModel an immutable type where all the properties are set in the constructor. Make the following
changes to the NewsStoryViewModel :
#nullable enable
public class NewsStoryViewModel
{
public NewsStoryViewModel(DateTimeOffset published, string title, string uri) =>
(Published, Title, Uri) = (published, title, uri);
Once that's done, you need to update the code that configures the AutoMapper so that it uses the constructor
rather than setting properties. Open NewsService.cs and look for the following code at the bottom of the file:
That code maps properties of the ISyndicationItem object to the NewsStoryViewModel properties. You want the
AutoMapper to provide the mapping using a constructor instead. Replace the above code with the following
automapper configuration:
#nullable enable
public class NewsStoryProfile : Profile
{
public NewsStoryProfile()
{
// Create the AutoMapper mapping profile between the 2 objects.
// ISyndicationItem.Id maps to NewsStoryViewModel.Uri.
CreateMap<ISyndicationItem, NewsStoryViewModel>()
.ForCtorParam("uri", opt => opt.MapFrom(src => src.Id));
}
Notice that because this class is small, and you've examined carefully, you should turn on the #nullable enable
directive above this class declaration. The change to the constructor could have broken something, so it's
worthwhile to run all the tests and test the application before moving on.
The first set of changes showed you how to discover when the original design indicated that variables shouldn't be
set to null . The technique is referred to as correct by construction . You declare that an object and its
properties cannot be null when it's constructed. The compiler's flow analysis provides assurance that those
properties aren't set to null after construction. Note that this constructor is called by external code, and that code
is nullable oblivious . The new syntax doesn't provide runtime checking. External code might circumvent the
compiler's flow analysis.
Other times, the structure of a class provides different clues to the intent. Open the Error.cshtml.cs file in the Pages
folder. The ErrorViewModel contains the following code:
Add the #nullable enable directive before the class declaration, and a #nullable restore directive after it. You'll
get one warning that RequestId is not initialized. By looking at the class, you should decide that the RequestId
property should be null in some cases. The existence of the ShowRequestId property indicates that missing values
are possible. Because null is valid, add the ? on the string type to indicate the RequestId property is a
nullable reference type. The final class looks like the following example:
#nullable enable
public class ErrorModel : PageModel
{
public string? RequestId { get; set; }
Check for the uses of the property, and you see that in the associated page, the property is checked for null before
rendering it in markup. That's a safe use of a nullable reference type, so you're done with this class.
if (!string.IsNullOrEmpty(feedUrl))
{
try
{
NewsItems = await _newsService.GetNews(feedUrl);
}
catch (UriFormatException)
{
ErrorText = "There was a problem parsing the URL.";
return;
}
catch (WebException ex) when (ex.Status == WebExceptionStatus.NameResolutionFailure)
{
ErrorText = "Unknown host name.";
return;
}
catch (WebException ex) when (ex.Status == WebExceptionStatus.ProtocolError)
{
ErrorText = "Syndication feed not found.";
return;
}
catch (AggregateException ae)
{
ae.Handle((x) =>
{
if (x is XmlException)
{
ErrorText = "There was a problem parsing the feed. Are you sure that URL is a
syndication feed?";
return true;
}
return false;
});
}
}
}
}
Add the #nullable enable directive and you'll see two warnings. Neither the ErrorText property nor the
NewsItems property is initialized. An examination of this class would lead you to believe that both properties
should be nullable reference types: Both have private setters. Exactly one is assigned in the OnGet method. Before
making changes, look at the consumers of both properties. In the page itself, the ErrorText is checked against null
before generating markup for any errors. The NewsItems collection is checked against null , and checked to
ensure the collection has items. A quick fix would be to make both properties nullable reference types. A better fix
would be to make the collection a nonnullable reference type, and add items to the existing collection when
retrieving news. The first fix is to add the ? to the string type for the ErrorText :
That change won't ripple through other code, because any access to the ErrorText property was already guarded
by null checks. Next, initialize the NewsItems list and remove the property setter, making it a readonly property:
That fixed the warning but introduced an error. The NewsItems list is now correct by construction , but the code
that sets the list in OnGet must change to match the new API. Instead of an assignment, call AddRange to add the
news items to the existing list:
NewsItems.AddRange(await _newsService.GetNews(feedUrl));
Using AddRange instead of an assignment means that the GetNews method can return an IEnumerable instead of
a List . That saves one allocation. Change the signature of the method, and remove the ToList call, as shown in
the following code sample:
public async Task<IEnumerable<NewsStoryViewModel>> GetNews(string feedUrl)
{
var news = new List<NewsStoryViewModel>();
var feedUri = new Uri(feedUrl);
// Something else
default:
break;
}
}
}
catch (AggregateException ae)
{
throw ae.Flatten();
}
}
Changing the signature breaks one of tests as well. Open the NewsServiceTests.cs file in the Services folder of
the SimpleFeedReader.Tests project. Navigate to the Returns_News_Stories_Given_Valid_Uri test and change the
type of the result variable to IEnumerable<NewsItem> . Changing the type means the Count property is no longer
available, so replace the Count property in the Assert with a call to Any() :
// Act
IEnumerable<NewsStoryViewModel> result =
await _newsService.GetNews(feedUrl);
// Assert
Assert.True(result.Any());
You'll need to add a using System.Linq statement to the beginning of the file as well.
This set of changes highlights special consideration when updating code that includes generic instantiations. Both
the list and the elements in the list of non-nullable types. Either or both could be nullable types. All the following
declarations are allowed:
List<NewsStoryViewModel> : nonnullable list of nonullable view models.
List<NewsStoryViewModel?> : nonnullable list of nullable view models.
List<NewsStoryViewModel>? : nullable list of nonnullable view models.
List<NewsStoryViewModel?>? : nullable list of nullable view models.
Interfaces with external code
You've made changes to the NewsService class, so turn on the #nullable enable annotation for that class. This
won't generate any new warnings. However, careful examination of the class helps to illustrate some of the
limitations of the compiler's flow analysis. Examine the constructor:
The IMapper parameter is typed as a nonnullable reference. It's called by ASP.NET Core infrastructure code, so the
compiler doesn't really know that the IMapper will never be null. The default ASP.NET Core dependency injection
(DI) container throws an exception if it can't resolve a necessary service, so the code is correct. The compiler can't
validate all calls to your public APIs, even if your code is compiled with nullable annotation contexts enabled.
Furthermore, your libraries may be consumed by projects that have not yet opted into using nullable reference
types. Validate inputs to public APIs even though you've declared them as nonnullable types.
C# 8.0 introduces async streams , which model a streaming source of data. Data streams often retrieve or
generate elements asynchronously. Async streams rely on new interfaces introduced in .NET Standard 2.1. These
interfaces are supported in .NET Core 3.0 and later. They provide a natural programming model for asynchronous
streaming data sources.
In this tutorial, you'll learn how to:
Create a data source that generates a sequence of data elements asynchronously.
Consume that data source asynchronously.
Support cancellation and captured contexts for asynchronous streams.
Recognize when the new interface and data source are preferred to earlier synchronous data sequences.
Prerequisites
You'll need to set up your machine to run .NET Core, including the C# 8.0 compiler. The C# 8 compiler is available
starting with Visual Studio 2019 version 16.3 or .NET Core 3.0 SDK.
You'll need to create a GitHub access token so that you can access the GitHub GraphQL endpoint. Select the
following permissions for your GitHub Access Token:
repo:status
public_repo
Save the access token in a safe place so you can use it to gain access to the GitHub API endpoint.
WARNING
Keep your personal access token secure. Any software with your personal access token could make GitHub API calls using
your access rights.
This tutorial assumes you're familiar with C# and .NET, including either Visual Studio or the .NET Core CLI.
try
{
var results = await runPagedQueryAsync(client, PagedIssueQuery, "docs",
cancellationSource.Token, progressReporter);
foreach(var issue in results)
Console.WriteLine(issue);
}
catch (OperationCanceledException)
{
Console.WriteLine("Work has been cancelled");
}
}
You can either set a GitHubKey environment variable to your personal access token, or you can replace the last
argument in the call to GenEnvVariable with your personal access token. Don't put your access code in source code
if you'll be sharing the source with others. Never upload access codes to a shared source repository.
After creating the GitHub client, the code in Main creates a progress reporting object and a cancellation token.
Once those objects are created, Main calls runPagedQueryAsync to retrieve the most recent 250 created issues. After
that task has finished, the results are displayed.
When you run the starter application, you can make some important observations about how this application runs.
You'll see progress reported for each page returned from GitHub. You can observe a noticeable pause before
GitHub returns each new page of issues. Finally, the issues are displayed only after all 10 pages have been retrieved
from GitHub.
Let's concentrate on the paging algorithm and async structure of the preceding code. (You can consult the GitHub
GraphQL documentation for details on the GitHub GraphQL API.) The runPagedQueryAsync method enumerates the
issues from most recent to oldest. It requests 25 issues per page and examines the pageInfo structure of the
response to continue with the previous page. That follows GraphQL's standard paging support for multi-page
responses. The response includes a pageInfo object that includes a hasPreviousPages value and a startCursor
value used to request the previous page. The issues are in the nodes array. The runPagedQueryAsync method
appends these nodes to an array that contains all the results from all pages.
After retrieving and restoring a page of results, runPagedQueryAsync reports progress and checks for cancellation. If
cancellation has been requested, runPagedQueryAsync throws an OperationCanceledException.
There are several elements in this code that can be improved. Most importantly, runPagedQueryAsync must allocate
storage for all the issues returned. This sample stops at 250 issues because retrieving all open issues would require
much more memory to store all the retrieved issues. The protocols for supporting progress reports and
cancellation make the algorithm harder to understand on its first reading. More types and APIs are involved. You
must trace the communications through the CancellationTokenSource and its associated CancellationToken to
understand where cancellation is requested and where it's granted.
The starter code processes each page as the page is retrieved, as shown in the following code:
finalResults.Merge(issues(results)["nodes"]);
progress?.Report(issuesReturned);
cancel.ThrowIfCancellationRequested();
You can also remove the declaration of finalResults earlier in this method and the return statement that follows
the loop you modified.
You've finished the changes to generate an async stream. The finished method should resemble the following code:
private static async IAsyncEnumerable<JToken> runPagedQueryAsync(GitHubClient client,
string queryText, string repoName)
{
var issueAndPRQuery = new GraphQLRequest
{
Query = queryText
};
issueAndPRQuery.Variables["repo_name"] = repoName;
Next, you change the code that consumes the collection to consume the async stream. Find the following code in
Main that processes the collection of issues:
try
{
var results = await runPagedQueryAsync(client, PagedIssueQuery, "docs",
cancellationSource.Token, progressReporter);
foreach(var issue in results)
Console.WriteLine(issue);
}
catch (OperationCanceledException)
{
Console.WriteLine("Work has been cancelled");
}
The new interface IAsyncEnumerator<T> derives from IAsyncDisposable. That means the preceding loop will
asynchronously dispose the stream when the loop finishes. You can imagine the loop looks like the following code:
int num = 0;
var enumerator = runPagedQueryAsync(client, PagedIssueQuery, "docs").GetEnumeratorAsync();
try
{
while (await enumerator.MoveNextAsync())
{
var issue = enumerator.Current;
Console.WriteLine(issue);
Console.WriteLine($"Received {++num} issues in total");
}
} finally
{
if (enumerator != null)
await enumerator.DisposeAsync();
}
By default, stream elements are processed in the captured context. If you want to disable capturing of the context,
use the TaskAsyncEnumerableExtensions.ConfigureAwait extension method. For more information about
synchronization contexts and capturing the current context, see the article on consuming the Task-based
asynchronous pattern.
Async streams support cancellation using the same protocol as other async methods. You would modify the
signature for the async iterator method as follows to support cancellation:
private static async IAsyncEnumerable<JToken> runPagedQueryAsync(GitHubClient client,
string queryText, string repoName, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
var issueAndPRQuery = new GraphQLRequest
{
Query = queryText
};
issueAndPRQuery.Variables["repo_name"] = repoName;
The EnumeratorCancellationAttribute attribute causes the compiler to generate code for the IAsyncEnumerator<T>
that makes the token passed to GetAsyncEnumerator visible to the body of the async iterator as that argument.
Inside runQueryAsync , you could examine the state of the token and cancel further work if requested.
You use another extension method, WithCancellation, to pass the cancellation token to the async stream. You would
modify the loop enumerating the issues as follows:
You can get the code for the finished tutorial from the dotnet/docs repository in the csharp/tutorials/AsyncStreams
folder.
C# 7 introduced basic pattern matching features. Those features are extended in C# 8 with new expressions and
patterns. You can write functionality that behaves as though you extended types that may be in other libraries.
Another use for patterns is to create functionality your application requires that isn't a fundamental feature of the
type being extended.
In this tutorial, you'll learn how to:
Recognize situations where pattern matching should be used.
Use pattern matching expressions to implement behavior based on types and property values.
Combine pattern matching with other techniques to create complete algorithms.
Prerequisites
You’ll need to set up your machine to run .NET Core, including the C# 8.0 compiler. The C# 8 compiler is available
starting with Visual Studio 2019 version 16.3 or .NET Core 3.0 SDK.
This tutorial assumes you're familiar with C# and .NET, including either Visual Studio or the .NET Core CLI.
namespace CommercialRegistration
{
public class DeliveryTruck
{
public int GrossWeightClass { get; set; }
}
}
namespace LiveryRegistration
{
public class Taxi
{
public int Fares { get; set; }
}
You can download the starter code from the dotnet/samples GitHub repository. You can see that the vehicle classes
are from different systems, and are in different namespaces. No common base class, other than System.Object can
be leveraged.
Create a new TollCalculator class, and implement pattern matching on the vehicle type to get the toll amount.
The following code shows the initial implementation of the TollCalculator .
using System;
using CommercialRegistration;
using ConsumerVehicleRegistration;
using LiveryRegistration;
namespace toll_calculator
{
public class TollCalculator
{
public decimal CalculateToll(object vehicle) =>
vehicle switch
{
Car c => 2.00m,
Taxi t => 3.50m,
Bus b => 5.00m,
DeliveryTruck t => 10.00m,
{ } => throw new ArgumentException(message: "Not a known vehicle type", paramName:
nameof(vehicle)),
null => throw new ArgumentNullException(nameof(vehicle))
};
}
}
The preceding code uses a switch expression (not the same as a switch statement) that tests the type pattern .
A switch expression begins with the variable, vehicle in the preceding code, followed by the switch keyword.
Next comes all the switch arms inside curly braces. The switch expression makes other refinements to the
syntax that surrounds the switch statement. The case keyword is omitted, and the result of each arm is an
expression. The last two arms show a new language feature. The { } case matches any non-null object that didn't
match an earlier arm. This arm catches any incorrect types passed to this method. The { } case must follow the
cases for each vehicle type. If the order were reversed, the { } case would take precedence. Finally, the null
pattern detects when a null is passed to this method. The null pattern can be last because the other type
patterns match only a non-null object of the correct type.
You can test this code using the following code in Program.cs :
using System;
using CommercialRegistration;
using ConsumerVehicleRegistration;
using LiveryRegistration;
namespace toll_calculator
{
class Program
{
static void Main(string[] args)
{
var tollCalc = new TollCalculator();
try
{
tollCalc.CalculateToll("this will fail");
}
catch (ArgumentException e)
{
Console.WriteLine("Caught an argument exception when using the wrong type");
}
try
{
tollCalc.CalculateToll(null);
}
catch (ArgumentNullException e)
{
Console.WriteLine("Caught an argument exception when using null");
}
}
}
}
That code is included in the starter project, but is commented out. Remove the comments, and you can test what
you've written.
You're starting to see how patterns can help you create algorithms where the code and the data are separate. The
switch expression tests the type and produces different values based on the results. That's only the beginning.
vehicle switch
{
Car { Passengers: 0} => 2.00m + 0.50m,
Car { Passengers: 1 } => 2.0m,
Car { Passengers: 2} => 2.0m - 0.50m,
Car c => 2.00m - 1.0m,
// ...
};
The first three cases test the type as a Car , then check the value of the Passengers property. If both match, that
expression is evaluated and returned.
You would also expand the cases for taxis in a similar manner:
vehicle switch
{
// ...
// ...
};
In the preceding example, the when clause was omitted on the final case.
Next, implement the occupancy rules by expanding the cases for buses, as shown in the following example:
vehicle switch
{
// ...
// ...
};
The toll authority isn't concerned with the number of passengers in the delivery trucks. Instead, they adjust the toll
amount based on the weight class of the trucks as follows:
Trucks over 5000 lbs are charged an extra $5.00.
Light trucks under 3000 lbs are given a $2.00 discount.
That rule is implemented with the following code:
vehicle switch
{
// ...
The preceding code shows the when clause of a switch arm. You use the when clause to test conditions other than
equality on a property. When you've finished, you'll have a method that looks much like the following:
vehicle switch
{
Car { Passengers: 0} => 2.00m + 0.50m,
Car { Passengers: 1} => 2.0m,
Car { Passengers: 2} => 2.0m - 0.50m,
Car c => 2.00m - 1.0m,
{ } => throw new ArgumentException(message: "Not a known vehicle type", paramName: nameof(vehicle)),
null => throw new ArgumentNullException(nameof(vehicle))
};
Many of these switch arms are examples of recursive patterns . For example, Car { Passengers: 1} shows a
constant pattern inside a property pattern.
You can make this code less repetitive by using nested switches. The Car and Taxi both have four different arms
in the preceding examples. In both cases, you can create a type pattern that feeds into a property pattern. This
technique is shown in the following code:
public decimal CalculateToll(object vehicle) =>
vehicle switch
{
Car c => c.Passengers switch
{
0 => 2.00m + 0.5m,
1 => 2.0m,
2 => 2.0m - 0.5m,
_ => 2.00m - 1.0m
},
{ } => throw new ArgumentException(message: "Not a known vehicle type", paramName: nameof(vehicle)),
null => throw new ArgumentNullException(nameof(vehicle))
};
In the preceding sample, using a recursive expression means you don't repeat the Car and Taxi arms containing
child arms that test the property value. This technique isn't used for the Bus and DeliveryTruck arms because
those arms are testing ranges for the property, not discrete values.
There are 16 different combinations of the three variables. By combining some of the conditions, you'll simplify the
final switch expression.
The system that collects the tolls uses a DateTime structure for the time when the toll was collected. Build member
methods that create the variables from the preceding table. The following function uses a pattern matching switch
expression to express whether a DateTime represents a weekend or a weekday:
That method works, but it's repetitious. You can simplify it, as shown in the following code:
private static bool IsWeekDay(DateTime timeOfToll) =>
timeOfToll.DayOfWeek switch
{
DayOfWeek.Saturday => false,
DayOfWeek.Sunday => false,
_ => true
};
Next, add a similar function to categorize the time into the blocks:
The previous method doesn't use pattern matching. It's clearer using a familiar cascade of if statements. You do
add a private enum to convert each range of time to a discrete value.
After you create those methods, you can use another switch expression with the tuple pattern to calculate the
pricing premium. You could build a switch expression with all 16 arms:
The above code works, but it can be simplified. All eight combinations for the weekend have the same toll. You can
replace all eight with the following line:
(false, _, _) => 1.0m,
Both inbound and outbound traffic have the same multiplier during the weekday daytime and overnight hours.
Those four switch arms can be replaced with the following two lines:
The code should look like the following code after those two changes:
Finally, you can remove the two rush hour times that pay the regular price. Once you remove those arms, you can
replace the false with a discard ( _ ) in the final switch arm. You'll have the following finished method:
This example highlights one of the advantages of pattern matching: the pattern branches are evaluated in order. If
you rearrange them so that an earlier branch handles one of your later cases, the compiler warns you about the
unreachable code. Those language rules made it easier to do the preceding simplifications with confidence that the
code didn't change.
Pattern matching makes some types of code more readable and offers an alternative to object-oriented techniques
when you can't add code to your classes. The cloud is causing data and functionality to live apart. The shape of the
data and the operations on it aren't necessarily described together. In this tutorial, you consumed existing data in
entirely different ways from its original function. Pattern matching gave you the ability to write functionality that
overrode those types, even though you couldn't extend them.
Next steps
You can download the finished code from the dotnet/samples GitHub repository. Explore patterns on your own and
add this technique into your regular coding activities. Learning these techniques gives you another way to
approach problems and create new functionality.
Console app
9/3/2020 • 12 minutes to read • Edit Online
This tutorial teaches you a number of features in .NET Core and the C# language. You'll learn:
The basics of the .NET Core CLI
The structure of a C# Console Application
Console I/O
The basics of File I/O APIs in .NET
The basics of the Task-based Asynchronous Programming in .NET
You'll build an application that reads a text file, and echoes the contents of that text file to the console. The output to
the console is paced to match reading it aloud. You can speed up or slow down the pace by pressing the '<' (less
than) or '>' (greater than) keys.
There are a lot of features in this tutorial. Let's build them one by one.
Prerequisites
Set up your machine to run .NET Core. You can find the installation instructions on the .NET Core downloads
page. You can run this application on Windows, Linux, macOS, or in a Docker container.
Install your favorite code editor.
This statement tells the compiler that any types from the System namespace are in scope. Like other Object
Oriented languages you may have used, C# uses namespaces to organize types. This Hello World program is no
different. You can see that the program is enclosed in the namespace with the name based on the name of the
current directory. For this tutorial, let's change the name of the namespace to TeleprompterConsole :
namespace TeleprompterConsole
This method uses types from two new namespaces. For this to compile you'll need to add the following two lines to
the top of the file:
using System.Collections.Generic;
using System.IO;
The IEnumerable<T> interface is defined in the System.Collections.Generic namespace. The File class is defined in
the System.IO namespace.
This method is a special type of C# method called an Iterator method. Enumerator methods return sequences that
are evaluated lazily. That means each item in the sequence is generated as it is requested by the code consuming
the sequence. Enumerator methods are methods that contain one or more yield return statements. The object
returned by the ReadFrom method contains the code to generate each item in the sequence. In this example, that
involves reading the next line of text from the source file, and returning that string. Each time the calling code
requests the next item from the sequence, the code reads the next line of text from the file and returns it. When the
file is completely read, the sequence indicates that there are no more items.
There are two other C# syntax elements that may be new to you. The using statement in this method manages
resource cleanup. The variable that is initialized in the using statement ( reader , in this example) must implement
the IDisposable interface. That interface defines a single method, Dispose , that should be called when the resource
should be released. The compiler generates that call when execution reaches the closing brace of the using
statement. The compiler-generated code ensures that the resource is released even if an exception is thrown from
the code in the block defined by the using statement.
The reader variable is defined using the var keyword. var defines an implicitly typed local variable. That means
the type of the variable is determined by the compile-time type of the object assigned to the variable. Here, that is
the return value from the OpenText(String) method, which is a StreamReader object.
Now, let's fill in the code to read the file in the Main method:
Run the program (using dotnet run ) and you can see every line printed out to the console.
Next, you need to modify how you consume the lines of the file, and add a delay after writing each word. Replace
the Console.WriteLine(line) statement in the Main method with the following block:
Console.Write(line);
if (!string.IsNullOrWhiteSpace(line))
{
var pause = Task.Delay(200);
// Synchronously waiting on a task is an
// anti-pattern. This will get fixed in later
// steps.
pause.Wait();
}
The Task class is in the System.Threading.Tasks namespace, so you need to add that using statement at the top of
file:
using System.Threading.Tasks;
Run the sample, and check the output. Now, each single word is printed, followed by a 200 ms delay. However, the
displayed output shows some issues because the source text file has several lines that have more than 80
characters without a line break. That can be hard to read while it's scrolling by. That's easy to fix. You'll just keep
track of the length of each line, and generate a new line whenever the line length reaches a certain threshold.
Declare a local variable after the declaration of words in the ReadFrom method that holds the line length:
var lineLength = 0;
Then, add the following code after the yield return word + " "; statement (before the closing brace):
lineLength += word.Length + 1;
if (lineLength > 70)
{
yield return Environment.NewLine;
lineLength = 0;
}
Run the sample, and you'll be able to read aloud at its pre-configured pace.
Async Tasks
In this final step, you'll add the code to write the output asynchronously in one task, while also running another
task to read input from the user if they want to speed up or slow down the text display, or stop the text display
altogether. This has a few steps in it and by the end, you'll have all the updates that you need. The first step is to
create an asynchronous Task returning method that represents the code you've created so far to read and display
the file.
Add this method to your Program class (it's taken from the body of your Main method):
You'll notice two changes. First, in the body of the method, instead of calling Wait() to synchronously wait for a task
to finish, this version uses the await keyword. In order to do that, you need to add the async modifier to the
method signature. This method returns a Task . Notice that there are no return statements that return a Task
object. Instead, that Task object is created by code the compiler generates when you use the await operator. You
can imagine that this method returns when it reaches an await . The returned Task indicates that the work has
not completed. The method resumes when the awaited task completes. When it has executed to completion, the
returned Task indicates that it is complete. Calling code can monitor that returned Task to determine when it has
completed.
You can call this new method in your Main method:
ShowTeleprompter().Wait();
Here, in Main , the code does synchronously wait. You should use the await operator instead of synchronously
waiting whenever possible. But, in a console application's Main method, you cannot use the await operator. That
would result in the application exiting before all tasks have completed.
NOTE
If you use C# 7.1 or later, you can create console applications with async Main method.
Next, you need to write the second asynchronous method to read from the Console and watch for the '<' (less
than), '>' (greater than) and 'X' or 'x' keys. Here's the method you add for that task:
This creates a lambda expression to represent an Action delegate that reads a key from the Console and modifies a
local variable representing the delay when the user presses the '<' (less than) or '>' (greater than) keys. The
delegate method finishes when user presses the 'X' or 'x' keys, which allow the user to stop the text display at any
time. This method uses ReadKey() to block and wait for the user to press a key.
To finish this feature, you need to create a new async Task returning method that starts both of these tasks (
GetInput and ShowTeleprompter ), and also manages the shared data between these two tasks.
It's time to create a class that can handle the shared data between these two tasks. This class contains two public
properties: the delay, and a flag Done to indicate that the file has been completely read:
namespace TeleprompterConsole
{
internal class TelePrompterConfig
{
public int DelayInMilliseconds { get; private set; } = 200;
Put that class in a new file, and enclose that class in the TeleprompterConsole namespace as shown above. You'll
also need to add a using static statement so that you can reference the Min and Max methods without the
enclosing class or namespace names. A using static statement imports the methods from one class. This is in
contrast with the using statements used up to this point that have imported all classes from a namespace.
Next, you need to update the ShowTeleprompter and GetInput methods to use the new config object. Write one
final Task returning async method to start both tasks and exit when the first task finishes:
The one new method here is the WhenAny(Task[]) call. That creates a Task that finishes as soon as any of the tasks
in its argument list completes.
Next, you need to update both the ShowTeleprompter and GetInput methods to use the config object for the
delay:
private static async Task ShowTeleprompter(TelePrompterConfig config)
{
var words = ReadFrom("sampleQuotes.txt");
foreach (var word in words)
{
Console.Write(word);
if (!string.IsNullOrWhiteSpace(word))
{
await Task.Delay(config.DelayInMilliseconds);
}
}
config.SetDone();
}
This new version of ShowTeleprompter calls a new method in the TeleprompterConfig class. Now, you need to
update Main to call RunTeleprompter instead of ShowTeleprompter :
RunTeleprompter().Wait();
Conclusion
This tutorial showed you a number of the features around the C# language and the .NET Core libraries related to
working in Console applications. You can build on this knowledge to explore more about the language, and the
classes introduced here. You've seen the basics of File and Console I/O, blocking and non-blocking use of the Task-
based asynchronous programming, a tour of the C# language and how C# programs are organized, and the .NET
Core CLI.
For more information about File I/O, see the File and Stream I/O topic. For more information about asynchronous
programming model used in this tutorial, see the Task-based Asynchronous Programming topic and the
Asynchronous programming topic.
REST client
9/3/2020 • 11 minutes to read • Edit Online
This tutorial teaches you a number of features in .NET Core and the C# language. You’ll learn:
The basics of the .NET Core CLI.
An overview of C# Language features.
Managing dependencies with NuGet
HTTP Communications
Processing JSON information
Managing configuration with Attributes.
You’ll build an application that issues HTTP Requests to a REST service on GitHub. You'll read information in JSON
format, and convert that JSON packet into C# objects. Finally, you'll see how to work with C# objects.
There are many features in this tutorial. Let’s build them one by one.
If you prefer to follow along with the final sample for this topic, you can download it. For download instructions,
see Samples and Tutorials.
Prerequisites
You’ll need to set up your machine to run .NET core. You can find the installation instructions on the .NET Core
Downloads page. You can run this application on Windows, Linux, macOS or in a Docker container. You’ll need to
install your favorite code editor. The descriptions below use Visual Studio Code, which is an open source, cross
platform editor. However, you can use whatever tools you are comfortable with.
This creates the starter files for a basic "Hello World" application. The project name is "WebAPIClient". As this is a
new project, none of the dependencies are in place. The first run will download the .NET Core framework, install a
development certificate, and run the NuGet package manager to restore missing dependencies.
Before you start making modifications, type dotnet run (see note) at the command prompt to run your
application. dotnet run automatically performs dotnet restore if your environment is missing dependencies. It
also performs dotnet build if your application needs to be rebuilt. After your initial setup, you will only need to
run dotnet restore or dotnet build when it makes sense for your project.
You'll need to add a using directive at the top of your Main method so that the C# compiler recognizes the Task
type:
using System.Threading.Tasks;
If you build your project at this point, you'll get a warning generated for this method, because it does not contain
any await operators and will run synchronously. Ignore that for now; you'll add await operators as you fill in the
method.
Next, update the Main method to call the ProcessRepositories method. The ProcessRepositories method returns
a task, and you shouldn't exit the program before that task finishes. Therefore, you must change the signature of
Main . Add the async modifier, and change the return type to Task . Then, in the body of the method, add a call to
ProcessRepositories . Add the await keyword to that method call:
Now, you have a program that does nothing, but does it asynchronously. Let's improve it.
First you need an object that is capable to retrieve data from the web; you can use a HttpClient to do that. This
object handles the request and the responses. Instantiate a single instance of that type in the Program class inside
the Program.cs file.
namespace WebAPIClient
{
class Program
{
private static readonly HttpClient client = new HttpClient();
Let's go back to the ProcessRepositories method and fill in a first version of it:
You'll need to also add two new using directives at the top of the file for this to compile:
using System.Net.Http;
using System.Net.Http.Headers;
This first version makes a web request to read the list of all repositories under the dotnet foundation organization.
(The gitHub ID for the .NET Foundation is 'dotnet'). The first few lines set up the HttpClient for this request. First, it
is configured to accept the GitHub JSON responses. This format is simply JSON. The next line adds a User Agent
header to all requests from this object. These two headers are checked by the GitHub server code, and are
necessary to retrieve information from GitHub.
After you've configured the HttpClient, you make a web request and retrieve the response. In this first version, you
use the HttpClient.GetStringAsync(String) convenience method. This convenience method starts a task that makes
the web request, and then when the request returns, it reads the response stream and extracts the content from the
stream. The body of the response is returned as a String. The string is available when the task completes.
The final two lines of this method await that task, and then print the response to the console. Build the app, and run
it. The build warning is gone now, because the ProcessRepositories now does contain an await operator. You'll
see a long display of JSON formatted text.
namespace WebAPIClient
{
public class Repository
{
public string name { get; set; }
}
}
Put the above code in a new file called 'repo.cs'. This version of the class represents the simplest path to process
JSON data. The class name and the member name match the names used in the JSON packet, instead of following
C# conventions. You'll fix that by providing some configuration attributes later. This class demonstrates another
important feature of JSON serialization and deserialization: Not all the fields in the JSON packet are part of this
class. The JSON serializer will ignore information that is not included in the class type being used. This feature
makes it easier to create types that work with only a subset of the fields in the JSON packet.
Now that you've created the type, let's deserialize it.
Next, you'll use the serializer to convert JSON into C# objects. Replace the call to GetStringAsync(String) in your
ProcessRepositories method with the following lines:
You're using new namespaces, so you'll need to add it at the top of the file as well:
using System.Collections.Generic;
using System.Text.Json;
Notice that you're now using GetStreamAsync(String) instead of GetStringAsync(String). The serializer uses a
stream instead of a string as its source. Let's explain a couple features of the C# language that are being used in the
second line of the preceding code snippet. The first argument to JsonSerializer.DeserializeAsync<TValue>(Stream,
JsonSerializerOptions, CancellationToken) is an await expression. (The other two parameters are optional and are
omitted in the code snippet.) Await expressions can appear almost anywhere in your code, even though up to now,
you've only seen them as part of an assignment statement. The Deserialize method is generic, which means you
must supply type arguments for what kind of objects should be created from the JSON text. In this example, you're
deserializing to a List<Repository> , which is another generic object, the System.Collections.Generic.List<T>. The
List<> class stores a collection of objects. The type argument declares the type of objects stored in the List<> .
The JSON text represents a collection of repo objects, so the type argument is Repository .
You're almost done with this section. Now that you've converted the JSON to C# objects, let's display the name of
each repository. Replace the lines that read:
Compile and run the application. It will print out the names of the repositories that are part of the .NET Foundation.
Controlling Serialization
Before you add more features, let's address the name property by using the [JsonPropertyName] attribute. Make
the following changes to the declaration of the name field in repo.cs:
[JsonPropertyName("name")]
public string Name { get; set; }
To use [JsonPropertyName] attribute, you will need to add the System.Text.Json.Serialization namespace to the
using directives:
using System.Text.Json.Serialization;
This change means you need to change the code that writes the name of each repository in program.cs:
Console.WriteLine(repo.Name);
Execute dotnet run to make sure you've got the mappings correct. You should see the same output as before.
Let's make one more change before adding new features. The ProcessRepositories method can do the async work
and return a collection of the repositories. Let's return the List<Repository> from that method, and move the code
that writes the information into the Main method.
Change the signature of ProcessRepositories to return a task whose result is a list of Repository objects:
Then, just return the repositories after processing the JSON response:
The compiler generates the Task<T> object for the return because you've marked this method as async . Then, let's
modify the Main method so that it captures those results and writes each repository name to the console. Your
Main method now looks like this:
[JsonPropertyName("html_url")]
public Uri GitHubHomeUrl { get; set; }
[JsonPropertyName("homepage")]
public Uri Homepage { get; set; }
[JsonPropertyName("watchers")]
public int Watchers { get; set; }
These properties have built-in conversions from the string type (which is what the JSON packets contain) to the
target type. The Uri type may be new to you. It represents a URI, or in this case, a URL. In the case of the Uri and
int types, if the JSON packet contains data that does not convert to the target type, the serialization action will
throw an exception.
Once you've added these, update the Main method to display those elements:
As a final step, let's add the information for the last push operation. This information is formatted in this fashion in
the JSON response:
2016-02-08T21:27:00Z
That format is in Coordinated Universal Time (UTC) so you'll get a DateTime value whose Kind property is Utc. If
you prefer a date represented in your time zone, you'll need to write a custom conversion method. First, define a
public property that will hold the UTC representation of the date and time in your Repository class and a
LastPush readonly property that returns the date converted to local time:
[JsonPropertyName("pushed_at")]
public DateTime LastPushUtc { get; set; }
Let's go over the new constructs we just defined. The LastPush property is defined using an expression-bodied
member for the get accessor. There is no set accessor. Omitting the set accessor is how you define a read-only
property in C#. (Yes, you can create write-only properties in C#, but their value is limited.)
Finally, add one more output statement in the console, and you're ready to build and run this app again:
Console.WriteLine(repo.LastPush);
Conclusion
This tutorial showed you how to make web requests, parse the result, and display properties of those results.
You've also added new packages as dependencies in your project. You've seen some of the features of the C#
language that support object-oriented techniques.
You don't have to run dotnet restore because it's run implicitly by all commands that require a restore to occur,
such as dotnet new , dotnet build , dotnet run , dotnet test , dotnet publish , and dotnet pack . To disable
implicit restore, use the --no-restore option.
The dotnet restore command is still useful in certain scenarios where explicitly restoring makes sense, such as
continuous integration builds in Azure DevOps Services or in build systems that need to explicitly control when the
restore occurs.
For information about how to manage NuGet feeds, see the dotnet restore documentation.
Inheritance in C# and .NET
9/3/2020 • 26 minutes to read • Edit Online
This tutorial introduces you to inheritance in C#. Inheritance is a feature of object-oriented programming languages
that allows you to define a base class that provides specific functionality (data and behavior) and to define derived
classes that either inherit or override that functionality.
Prerequisites
This tutorial assumes that you've installed the .NET Core SDK. Visit the .NET Core Downloads page to download it.
You also need a code editor. This tutorial uses Visual Studio Code, although you can use any code editor of your
choice.
using System;
public class A
{
private int value = 10;
public class B : A
{
public int GetValue()
{
return this.value;
}
}
}
public class C : A
{
// public int GetValue()
// {
// return this.value;
// }
}
public class B : A
{ }
Derived classes can also override inherited members by providing an alternate implementation. In order to be able
to override a member, the member in the base class must be marked with the virtual keyword. By default, base
class members are not marked as virtual and cannot be overridden. Attempting to override a non-virtual
member, as the following example does, generates compiler error CS0506: "<member> cannot override inherited
member <member> because it is not marked virtual, abstract, or override.
public class A
{
public void Method1()
{
// Do something.
}
}
public class B : A
{
public override void Method1() // Generates CS0506.
{
// Do something else.
}
}
In some cases, a derived class must override the base class implementation. Base class members marked with the
abstract keyword require that derived classes override them. Attempting to compile the following example
generates compiler error CS0534, "<class> does not implement inherited abstract member <member>", because
class B provides no implementation for A.Method1 .
using System;
Implicit inheritance
Besides any types that they may inherit from through single inheritance, all types in the .NET type system implicitly
inherit from Object or a type derived from it. The common functionality of Object is available to any type.
To see what implicit inheritance means, let's define a new class, SimpleClass , that is simply an empty class
definition:
You can then use reflection (which lets you inspect a type's metadata to get information about that type) to get a list
of the members that belong to the SimpleClass type. Although you haven't defined any members in your
SimpleClass class, output from the example indicates that it actually has nine members. One of these members is a
parameterless (or default) constructor that is automatically supplied for the SimpleClass type by the C# compiler.
The remaining eight are members of Object, the type from which all classes and interfaces in the .NET type system
ultimately implicitly inherit.
using System;
using System.Reflection;
Implicit inheritance from the Object class makes these methods available to the SimpleClass class:
The public ToString method, which converts a SimpleClass object to its string representation, returns the
fully qualified type name. In this case, the ToString method returns the string "SimpleClass".
Three methods that test for equality of two objects: the public instance Equals(Object) method, the public
static Equals(Object, Object) method, and the public static ReferenceEquals(Object, Object) method. By
default, these methods test for reference equality; that is, to be equal, two object variables must refer to the
same object.
The public GetHashCode method, which computes a value that allows an instance of the type to be used in
hashed collections.
The public GetType method, which returns a Type object that represents the SimpleClass type.
The protected Finalize method, which is designed to release unmanaged resources before an object's
memory is reclaimed by the garbage collector.
The protected MemberwiseClone method, which creates a shallow clone of the current object.
Because of implicit inheritance, you can call any inherited member from a SimpleClass object just as if it was
actually a member defined in the SimpleClass class. For instance, the following example calls the
SimpleClass.ToString method, which SimpleClass inherits from Object.
using System;
The following table lists the categories of types that you can create in C# and the types from which they implicitly
inherit. Each base type makes a different set of members available through inheritance to implicitly derived types.
T Y P E C AT EGO RY IM P L IC IT LY IN H ERIT S F RO M
class Object
NOTE
A class or struct can implement one or more interfaces. While interface implementation is often presented as a workaround
for single inheritance or as a way of using inheritance with structs, it is intended to express a different relationship (a "can do"
relationship) between an interface and its implementing type than inheritance. An interface defines a subset of functionality
(such as the ability to test for equality, to compare or sort objects, or to support culture-sensitive parsing and formatting)
that the interface makes available to its implementing types.
Note that "is a" also expresses the relationship between a type and a specific instantiation of that type. In the
following example, Automobile is a class that has three unique read-only properties: Make , the manufacturer of
the automobile; Model , the kind of automobile; and Year , its year of manufacture. Your Automobile class also has
a constructor whose arguments are assigned to the property values, and it overrides the Object.ToString method to
produce a string that uniquely identifies the Automobile instance rather than the Automobile class.
using System;
if (model == null)
throw new ArgumentNullException("The model cannot be null.");
else if (String.IsNullOrWhiteSpace(model))
throw new ArgumentException("model cannot be an empty string or have space characters only.");
Model = model;
In this case, you shouldn't rely on inheritance to represent specific car makes and models. For example, you don't
need to define a Packard type to represent automobiles manufactured by the Packard Motor Car Company.
Instead, you can represent them by creating an Automobile object with the appropriate values passed to its class
constructor, as the following example does.
using System;
An is-a relationship based on inheritance is best applied to a base class and to derived classes that add additional
members to the base class or that require additional functionality not present in the base class.
using System;
if (String.IsNullOrWhiteSpace(title))
throw new ArgumentException("The title is required.");
Title = title;
Type = type;
}
A constructor
Because the Publication class is abstract , it cannot be instantiated directly from code like the following
example:
However, its instance constructor can be called directly from derived class constructors, as the source code
for the Book class shows.
Two publication-related properties
Title is a read-only String property whose value is supplied by calling the Publication constructor.
Pages is a read-write Int32 property that indicates how many total pages the publication has. The value is
stored in a private field named totalPages . It must be a positive number or an
ArgumentOutOfRangeException is thrown.
Publisher-related members
Two read-only properties, Publisher and Type . The values are originally supplied by the call to the
Publication class constructor.
Publishing-related members
Two methods, Publish and GetPublicationDate , set and return the publication date. The Publish method
sets a private published flag to true when it is called and assigns the date passed to it as an argument to
the private datePublished field. The GetPublicationDate method returns the string "NYP" if the published
flag is false , and the value of the datePublished field if it is true .
Copyright-related members
The Copyright method takes the name of the copyright holder and the year of the copyright as arguments
and assigns them to the CopyrightName and CopyrightDate properties.
An override of the ToString method
If a type does not override the Object.ToString method, it returns the fully qualified name of the type, which
is of little use in differentiating one instance from another. The Publication class overrides Object.ToString
to return the value of the Title property.
The following figure illustrates the relationship between your base Publication class and its implicitly inherited
Object class.
public Book(string title, string isbn, string author, string publisher) : base(title, publisher,
PublicationType.Book)
{
// isbn argument must be a 10- or 13-character numeric string without "-" characters.
// We could also determine whether the ISBN is valid by comparing its checksum digit
// with a computed checksum.
//
if (! String.IsNullOrEmpty(isbn)) {
// Determine if ISBN length is correct.
if (! (isbn.Length == 10 | isbn.Length == 13))
throw new ArgumentException("The ISBN must be a 10- or 13-character numeric string.");
ulong nISBN = 0;
if (! UInt64.TryParse(isbn, out nISBN))
throw new ArgumentException("The ISBN can consist of numeric characters only.");
}
ISBN = isbn;
Author = author;
}
if (currency.Length != 3)
throw new ArgumentException("The ISO currency symbol is a 3-character string.");
Currency = currency;
return oldValue;
}
public override string ToString() => $"{(String.IsNullOrEmpty(Author) ? "" : Author + ", ")}{Title}";
}
In addition to the members that it inherits from Publication , the Book class defines the following unique
members and member overrides:
Two constructors
The two Book constructors share three common parameters. Two, title and publisher, correspond to
parameters of the Publication constructor. The third is author, which is stored to a public immutable
Author property. One constructor includes an isbn parameter, which is stored in the ISBN auto-property.
The first constructor uses the this keyword to call the other constructor. Constructor chaining is a common
pattern in defining constructors. Constructors with fewer parameters provide default values when calling the
constructor with the greatest number of parameters.
The second constructor uses the base keyword to pass the title and publisher name to the base class
constructor. If you don't make an explicit call to a base class constructor in your source code, the C# compiler
automatically supplies a call to the base class' default or parameterless constructor.
A read-only ISBN property, which returns the Book object's International Standard Book Number, a unique
10- or 13-digit number. The ISBN is supplied as an argument to one of the Book constructors. The ISBN is
stored in a private backing field, which is auto-generated by the compiler.
A read-only Author property. The author name is supplied as an argument to both Book constructors and
is stored in the property.
Two read-only price-related properties, Price and Currency . Their values are provided as arguments in a
SetPrice method call. The Currency property is the three-digit ISO currency symbol (for example, USD for
the U.S. dollar). ISO currency symbols can be retrieved from the ISOCurrencySymbol property. Both of these
properties are externally read-only, but both can be set by code in the Book class.
A SetPrice method, which sets the values of the Price and Currency properties. Those values are
returned by those same properties.
Overrides to the ToString method (inherited from Publication ) and the Object.Equals(Object) and
GetHashCode methods (inherited from Object).
Unless it is overridden, the Object.Equals(Object) method tests for reference equality. That is, two object
variables are considered to be equal if they refer to the same object. In the Book class, on the other hand,
two Book objects should be equal if they have the same ISBN.
When you override the Object.Equals(Object) method, you must also override the GetHashCode method,
which returns a value that the runtime uses to store items in hashed collections for efficient retrieval. The
hash code should return a value that's consistent with the test for equality. Since you've overridden
Object.Equals(Object) to return true if the ISBN properties of two Book objects are equal, you return the
hash code computed by calling the GetHashCode method of the string returned by the ISBN property.
The following figure illustrates the relationship between the Book class and Publication , its base class.
You can now instantiate a Book object, invoke both its unique and inherited members, and pass it as an argument
to a method that expects a parameter of type Publication or of type Book , as the following example shows.
using System;
using static System.Console;
var book2 = new Book("The Tempest", "Classic Works Press", "Shakespeare, William");
Write($"{book.Title} and {book2.Title} are the same publication: " +
$"{((Publication) book).Equals(book2)}");
}
You can then derive some classes from Shape that represent specific shapes. The following example defines three
classes, Triangle , Rectangle , and Circle . Each uses a formula unique for that particular shape to compute the
area and perimeter. Some of the derived classes also define properties, such as Rectangle.Diagonal and
Circle.Diameter , that are unique to the shape that they represent.
using System;
The following example uses objects derived from Shape . It instantiates an array of objects derived from Shape and
calls the static methods of the Shape class, which wraps return Shape property values. The runtime retrieves
values from the overridden properties of the derived types. The example also casts each Shape object in the array
to its derived type and, if the cast succeeds, retrieves properties of that particular subclass of Shape .
using System;
See also
Inheritance (C# Programming Guide)
Work with Language-Integrated Query (LINQ)
9/3/2020 • 15 minutes to read • Edit Online
Introduction
This tutorial teaches you features in .NET Core and the C# language. You’ll learn how to:
Generate sequences with LINQ.
Write methods that can be easily used in LINQ queries.
Distinguish between eager and lazy evaluation.
You'll learn these techniques by building an application that demonstrates one of the basic skills of any magician:
the faro shuffle. Briefly, a faro shuffle is a technique where you split a card deck exactly in half, then the shuffle
interleaves each one card from each half to rebuild the original deck.
Magicians use this technique because every card is in a known location after each shuffle, and the order is a
repeating pattern.
For your purposes, it is a light hearted look at manipulating sequences of data. The application you'll build
constructs a card deck and then performs a sequence of shuffles, writing the sequence out each time. You'll also
compare the updated order to the original order.
This tutorial has multiple steps. After each step, you can run the application and see the progress. You can also see
the completed sample in the dotnet/samples GitHub repository. For download instructions, see Samples and
Tutorials.
Prerequisites
You’ll need to set up your machine to run .NET core. You can find the installation instructions on the .NET Core
Download page. You can run this application on Windows, Ubuntu Linux, or OS X, or in a Docker container. You’ll
need to install your favorite code editor. The descriptions below use Visual Studio Code which is an open source,
cross-platform editor. However, you can use whatever tools you are comfortable with.
// Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
If these three lines ( using statements) aren't at the top of the file, our program will not compile.
Now that you have all of the references that you'll need, consider what constitutes a deck of cards. Commonly, a
deck of playing cards has four suits, and each suit has thirteen values. Normally, you might consider creating a
Card class right off the bat and populating a collection of Card objects by hand. With LINQ, you can be more
concise than the usual way of dealing with creating a deck of cards. Instead of creating a Card class, you can
create two sequences to represent suits and ranks, respectively. You'll create a really simple pair of iterator
methods that will generate the ranks and suits as IEnumerable<T>s of strings:
// Program.cs
// The Main() method
Place these underneath the Main method in your Program.cs file. These two methods both utilize the
yield return syntax to produce a sequence as they run. The compiler builds an object that implements
IEnumerable<T> and generates the sequence of strings as they are requested.
Now, use these iterator methods to create the deck of cards. You'll place the LINQ query in our Main method.
Here's a look at it:
// Program.cs
static void Main(string[] args)
{
var startingDeck = from s in Suits()
from r in Ranks()
select new { Suit = s, Rank = r };
// Display each card that we've generated and placed in startingDeck in the console
foreach (var card in startingDeck)
{
Console.WriteLine(card);
}
}
The multiple from clauses produce a SelectMany, which creates a single sequence from combining each element
in the first sequence with each element in the second sequence. The order is important for our purposes. The first
element in the first source sequence (Suits) is combined with every element in the second sequence (Ranks). This
produces all thirteen cards of first suit. That process is repeated with each element in the first sequence (Suits). The
end result is a deck of cards ordered by suits, followed by values.
It's important to keep in mind that whether you choose to write your LINQ in the query syntax used above or use
method syntax instead, it's always possible to go from one form of syntax to the other. The above query written in
query syntax can be written in method syntax as:
var startingDeck = Suits().SelectMany(suit => Ranks().Select(rank => new { Suit = suit, Rank = rank }));
The compiler translates LINQ statements written with query syntax into the equivalent method call syntax.
Therefore, regardless of your syntax choice, the two versions of the query produce the same result. Choose which
syntax works best for your situation: for instance, if you're working in a team where some of the members have
difficulty with method syntax, try to prefer using query syntax.
Go ahead and run the sample you've built at this point. It will display all 52 cards in the deck. You may find it very
helpful to run this sample under a debugger to observe how the Suits() and Ranks() methods execute. You can
clearly see that each string in each sequence is generated only as it is needed.
// Program.cs
public static void Main(string[] args)
{
var startingDeck = from s in Suits()
from r in Ranks()
select new { Suit = s, Rank = r };
// 52 cards in a deck, so 52 / 2 = 26
var top = startingDeck.Take(26);
var bottom = startingDeck.Skip(26);
}
However, there's no shuffle method to take advantage of in the standard library, so you'll have to write your own.
The shuffle method you'll be creating illustrates several techniques that you'll use with LINQ-based programs, so
each part of this process will be explained in steps.
In order to add some functionality to how you interact with the IEnumerable<T> you'll get back from LINQ queries,
you'll need to write some special kinds of methods called extension methods. Briefly, an extension method is a
special purpose static method that adds new functionality to an already-existing type without having to modify the
original type you want to add functionality to.
Give your extension methods a new home by adding a new static class file to your program called Extensions.cs ,
and then start building out the first extension method:
// Extensions.cs
using System;
using System.Collections.Generic;
using System.Linq;
namespace LinqFaroShuffle
{
public static class Extensions
{
public static IEnumerable<T> InterleaveSequenceWith<T>(this IEnumerable<T> first, IEnumerable<T>
second)
{
// Your implementation will go here soon enough
}
}
}
You can see the addition of the this modifier on the first argument to the method. That means you call the
method as though it were a member method of the type of the first argument. This method declaration also
follows a standard idiom where the input and output types are IEnumerable<T> . That practice enables LINQ
methods to be chained together to perform more complex queries.
Naturally, since you split the deck into halves, you'll need to join those halves together. In code, this means you'll be
enumerating both of the sequences you acquired through Take and Skip at once, interleaving the elements, and
creating one sequence: your now-shuffled deck of cards. Writing a LINQ method that works with two sequences
requires that you understand how IEnumerable<T> works.
The IEnumerable<T> interface has one method: GetEnumerator. The object returned by GetEnumerator has a
method to move to the next element, and a property that retrieves the current element in the sequence. You will
use those two members to enumerate the collection and return the elements. This Interleave method will be an
iterator method, so instead of building a collection and returning the collection, you'll use the yield return syntax
shown above.
Here's the implementation of that method:
public static IEnumerable<T> InterleaveSequenceWith<T>
(this IEnumerable<T> first, IEnumerable<T> second)
{
var firstIter = first.GetEnumerator();
var secondIter = second.GetEnumerator();
Now that you've written this method, go back to the Main method and shuffle the deck once:
// Program.cs
public static void Main(string[] args)
{
var startingDeck = from s in Suits()
from r in Ranks()
select new { Suit = s, Rank = r };
Comparisons
How many shuffles it takes to set the deck back to its original order? To find out, you'll need to write a method that
determines if two sequences are equal. After you have that method, you'll need to place the code that shuffles the
deck in a loop, and check to see when the deck is back in order.
Writing a method to determine if the two sequences are equal should be straightforward. It's a similar structure to
the method you wrote to shuffle the deck. Only this time, instead of yield return ing each element, you'll compare
the matching elements of each sequence. When the entire sequence has been enumerated, if every element
matches, the sequences are the same:
public static bool SequenceEquals<T>
(this IEnumerable<T> first, IEnumerable<T> second)
{
var firstIter = first.GetEnumerator();
var secondIter = second.GetEnumerator();
return true;
}
This shows a second LINQ idiom: terminal methods. They take a sequence as input (or in this case, two sequences),
and return a single scalar value. When using terminal methods, they are always the final method in a chain of
methods for a LINQ query, hence the name "terminal".
You can see this in action when you use it to determine when the deck is back in its original order. Put the shuffle
code inside a loop, and stop when the sequence is back in its original order by applying the SequenceEquals()
method. You can see it would always be the final method in any query, because it returns a single value instead of a
sequence:
// Program.cs
static void Main(string[] args)
{
// Query for building the deck
var times = 0;
// We can re-use the shuffle variable from earlier, or you can make a new one
shuffle = startingDeck;
do
{
shuffle = shuffle.Take(26).InterleaveSequenceWith(shuffle.Skip(26));
} while (!startingDeck.SequenceEquals(shuffle));
Console.WriteLine(times);
}
Run the code you've got so far and take note of how the deck rearranges on each shuffle. After 8 shuffles
(iterations of the do-while loop), the deck returns to the original configuration it was in when you first created it
from the starting LINQ query.
Optimizations
The sample you've built so far executes an out shuffle, where the top and bottom cards stay the same on each run.
Let's make one change: we'll use an in shuffle instead, where all 52 cards change position. For an in shuffle, you
interleave the deck so that the first card in the bottom half becomes the first card in the deck. That means the last
card in the top half becomes the bottom card. This is a simple change to a singular line of code. Update the current
shuffle query by switching the positions of Take and Skip. This will change the order of the top and bottom halves
of the deck:
shuffle = shuffle.Skip(26).InterleaveSequenceWith(shuffle.Take(26));
Run the program again, and you'll see that it takes 52 iterations for the deck to reorder itself. You'll also start to
notice some serious performance degradations as the program continues to run.
There are a number of reasons for this. You can tackle one of the major causes of this performance drop: inefficient
use of lazy evaluation.
Briefly, lazy evaluation states that the evaluation of a statement is not performed until its value is needed. LINQ
queries are statements that are evaluated lazily. The sequences are generated only as the elements are requested.
Usually, that's a major benefit of LINQ. However, in a use such as this program, this causes exponential growth in
execution time.
Remember that we generated the original deck using a LINQ query. Each shuffle is generated by performing three
LINQ queries on the previous deck. All these are performed lazily. That also means they are performed again each
time the sequence is requested. By the time you get to the 52nd iteration, you're regenerating the original deck
many, many times. Let's write a log to demonstrate this behavior. Then, you'll fix it.
In your file, type in or copy the method below. This extension method creates a new file called
Extensions.cs
debug.log within your project directory and records what query is currently being executed to the log file. This
extension method can be appended to any query to mark that the query executed.
return sequence;
}
You will see a red squiggle under File , meaning it doesn't exist. It won't compile, since the compiler doesn't know
what File is. To solve this problem, make sure to add the following line of code under the very first line in
Extensions.cs :
using System.IO;
This should solve the issue and the red error disappears.
Next, instrument the definition of each query with a log message:
// Program.cs
public static void Main(string[] args)
{
var startingDeck = (from s in Suits().LogQuery("Suit Generation")
from r in Ranks().LogQuery("Rank Generation")
select new { Suit = s, Rank = r }).LogQuery("Starting Deck");
Console.WriteLine();
var times = 0;
var shuffle = startingDeck;
do
{
// Out shuffle
/*
shuffle = shuffle.Take(26)
.LogQuery("Top Half")
.InterleaveSequenceWith(shuffle.Skip(26)
.LogQuery("Bottom Half"))
.LogQuery("Shuffle");
*/
// In shuffle
shuffle = shuffle.Skip(26).LogQuery("Bottom Half")
.InterleaveSequenceWith(shuffle.Take(26).LogQuery("Top Half"))
.LogQuery("Shuffle");
times++;
Console.WriteLine(times);
} while (!startingDeck.SequenceEquals(shuffle));
Console.WriteLine(times);
}
Notice that you don't log every time you access a query. You log only when you create the original query. The
program still takes a long time to run, but now you can see why. If you run out of patience running the in shuffle
with logging turned on, switch back to the out shuffle. You'll still see the lazy evaluation effects. In one run, it
executes 2592 queries, including all the value and suit generation.
You can improve the performance of the code here to reduce the number of executions you make. A simple fix you
can make is to cache the results of the original LINQ query that constructs the deck of cards. Currently, you're
executing the queries again and again every time the do-while loop goes through an iteration, re-constructing the
deck of cards and reshuffling it every time. To cache the deck of cards, you can leverage the LINQ methods ToArray
and ToList; when you append them to the queries, they'll perform the same actions you've told them to, but now
they'll store the results in an array or a list, depending on which method you choose to call. Append the LINQ
method ToArray to both queries and run the program again:
public static void Main(string[] args)
{
var startingDeck = (from s in Suits().LogQuery("Suit Generation")
from r in Ranks().LogQuery("Value Generation")
select new { Suit = s, Rank = r })
.LogQuery("Starting Deck")
.ToArray();
Console.WriteLine();
var times = 0;
var shuffle = startingDeck;
do
{
/*
shuffle = shuffle.Take(26)
.LogQuery("Top Half")
.InterleaveSequenceWith(shuffle.Skip(26).LogQuery("Bottom Half"))
.LogQuery("Shuffle")
.ToArray();
*/
shuffle = shuffle.Skip(26)
.LogQuery("Bottom Half")
.InterleaveSequenceWith(shuffle.Take(26).LogQuery("Top Half"))
.LogQuery("Shuffle")
.ToArray();
times++;
Console.WriteLine(times);
} while (!startingDeck.SequenceEquals(shuffle));
Console.WriteLine(times);
}
Now the out shuffle is down to 30 queries. Run again with the in shuffle and you'll see similar improvements: it
now executes 162 queries.
Please note that this example is designed to highlight the use cases where lazy evaluation can cause performance
difficulties. While it's important to see where lazy evaluation can impact code performance, it's equally important
to understand that not all queries should run eagerly. The performance hit you incur without using ToArray is
because each new arrangement of the deck of cards is built from the previous arrangement. Using lazy evaluation
means each new deck configuration is built from the original deck, even executing the code that built the
startingDeck . That causes a large amount of extra work.
In practice, some algorithms run well using eager evaluation, and others run well using lazy evaluation. For daily
usage, lazy evaluation is usually a better choice when the data source is a separate process, like a database engine.
For databases, lazy evaluation allows more complex queries to execute only one round trip to the database process
and back to the rest of your code. LINQ is flexible whether you choose to utilize lazy or eager evaluation, so
measure your processes and pick whichever kind of evaluation gives you the best performance.
Conclusion
In this project, you covered:
using LINQ queries to aggregate data into a meaningful sequence
writing Extension methods to add our own custom functionality to LINQ queries
locating areas in our code where our LINQ queries might run into performance issues like degraded speed
lazy and eager evaluation in regards to LINQ queries and the implications they might have on query
performance
Aside from LINQ, you learned a bit about a technique magicians use for card tricks. Magicians use the Faro shuffle
because they can control where every card moves in the deck. Now that you know, don't spoil it for everyone else!
For more information on LINQ, see:
Language Integrated Query (LINQ)
Introduction to LINQ
Basic LINQ Query Operations (C#)
Data Transformations With LINQ (C#)
Query Syntax and Method Syntax in LINQ (C#)
C# Features That Support LINQ
Use Attributes in C#
1/14/2020 • 7 minutes to read • Edit Online
Attributes provide a way of associating information with code in a declarative way. They can also provide a
reusable element that can be applied to a variety of targets.
Consider the [Obsolete] attribute. It can be applied to classes, structs, methods, constructors, and more. It declares
that the element is obsolete. It's then up to the C# compiler to look for this attribute, and do some action in
response.
In this tutorial, you'll be introduced to how to add attributes to your code, how to create and use your own
attributes, and how to use some attributes that are built into .NET Core.
Prerequisites
You’ll need to set up your machine to run .NET core. You can find the installation instructions on the .NET Core
Downloads page. You can run this application on Windows, Ubuntu Linux, macOS or in a Docker container. You’ll
need to install your favorite code editor. The descriptions below use Visual Studio Code which is an open source,
cross platform editor. However, you can use whatever tools you are comfortable with.
This command will create bare-bones .NET core project files. You will need to execute dotnet restore to restore
the dependencies needed to compile this project.
You don't have to run dotnet restore because it's run implicitly by all commands that require a restore to occur,
such as dotnet new , dotnet build , dotnet run , dotnet test , dotnet publish , and dotnet pack . To disable
implicit restore, use the --no-restore option.
The dotnet restore command is still useful in certain scenarios where explicitly restoring makes sense, such as
continuous integration builds in Azure DevOps Services or in build systems that need to explicitly control when the
restore occurs.
For information about how to manage NuGet feeds, see the dotnet restore documentation.
To execute the program, use dotnet run . You should see "Hello, World" output to the console.
Note that while the class is called ObsoleteAttribute , it's only necessary to use [Obsolete] in the code. This is a
convention that C# follows. You can use the full name [ObsoleteAttribute] if you choose.
When marking a class obsolete, it's a good idea to provide some information as to why it's obsolete, and/or what
to use instead. Do this by passing a string parameter to the Obsolete attribute.
The string is being passed as an argument to an ObsoleteAttribute constructor, just as if you were writing
var attr = new ObsoleteAttribute("some string") .
Parameters to an attribute constructor are limited to simple types/literals:
bool, int, double, string, Type, enums, etc and arrays of those types. You can not use an expression or a
variable. You are free to use positional or named parameters.
With the above, I can now use [MySpecial] (or [MySpecialAttribute] ) as an attribute elsewhere in the code base.
[MySpecial]
public class SomeOtherClass
{
}
Attributes in the .NET base class library like ObsoleteAttribute trigger certain behaviors within the compiler.
However, any attribute you create acts only as metadata, and doesn't result in any code within the attribute class
being executed. It's up to you to act on that metadata elsewhere in your code (more on that later in the tutorial).
There is a 'gotcha' here to watch out for. As mentioned above, only certain types are allowed to be passed as
arguments when using attributes. However, when creating an attribute type, the C# compiler won't stop you from
creating those parameters. In the below example, I've created an attribute with a constructor that compiles just fine.
However, you will be unable to use this constructor with attribute syntax.
[Gotcha(new Foo(), "test")] // does not compile
public class AttributeFail
{
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class MyAttributeForClassAndStructOnly : Attribute
{
}
If you attempt to put the above attribute on something that's not a class or a struct, you will get a compiler error
like
Attribute 'MyAttributeForClassAndStructOnly' is not valid on this declaration type. It is only valid on 'class,
struct' declarations
Once you have a TypeInfo object (or a MemberInfo , FieldInfo , etc), you can use the GetCustomAttributes method.
This will return a collection of Attribute objects. You can also use GetCustomAttribute and specify an Attribute
type.
Here's an example of using GetCustomAttributes on a MemberInfo instance for MyClass (which we saw earlier has
an [Obsolete] attribute on it).
That will print to console: Attribute on MyClass: ObsoleteAttribute . Try adding other attributes to MyClass .
It's important to note that these Attribute objects are instantiated lazily. That is, they won't be instantiated until
you use GetCustomAttribute or GetCustomAttributes . They are also instantiated each time. Calling
GetCustomAttributes twice in a row will return two different instances of ObsoleteAttribute .
In the above code, you don't have to have a literal "Name" string. This can help prevent typo-related bugs and also
makes for smoother refactoring/renaming.
Summary
Attributes bring declarative power to C#, but they are a meta-data form of code and don't act by themselves.
A tour of the C# language
9/3/2020 • 11 minutes to read • Edit Online
C# (pronounced "See Sharp") is a modern, object-oriented, and type-safe programming language. C# has its roots
in the C family of languages and will be immediately familiar to C, C++, Java, and JavaScript programmers. This
tour provides an overview of the major components of the language in C# 8 and earlier. If you want to explore the
language through interactive examples, try the introduction to C# tutorials.
C# is an object-oriented, component-oriented programming language. C# provides language constructs to
directly support these concepts, making C# a natural language in which to create and use software components.
Since its origin, C# has added features to support new workloads and emerging software design practices.
Several C# features aid in the construction of robust and durable applications. Garbage collection automatically
reclaims memory occupied by unreachable unused objects. Exception handling provides a structured and
extensible approach to error detection and recovery. Lambda expressions support functional programming
techniques. Quer y syntax creates a common pattern for working with data from any source. Language support
for asynchronous operations provides syntax for building distributed systems. Pattern matching provides
syntax to easily separate data from algorithms in modern distributed systems. C# has a unified type system . All
C# types, including primitive types such as int and double , inherit from a single root object type. All types
share a set of common operations. Values of any type can be stored, transported, and operated upon in a
consistent manner. Furthermore, C# supports both user-defined reference types and value types. C# allows
dynamic allocation of objects and in-line storage of lightweight structures.
C# emphasizes versioning to ensure programs and libraries can evolve over time in a compatible manner. Aspects
of C#'s design that were directly influenced by versioning considerations include the separate virtual and
override modifiers, the rules for method overload resolution, and support for explicit interface member
declarations.
Hello world
The "Hello, World" program is traditionally used to introduce a programming language. Here it is in C#:
using System;
class Hello
{
static void Main()
{
Console.WriteLine("Hello, World");
}
}
The "Hello, World" program starts with a using directive that references the System namespace. Namespaces
provide a hierarchical means of organizing C# programs and libraries. Namespaces contain types and other
namespaces—for example, the System namespace contains a number of types, such as the Console class
referenced in the program, and a number of other namespaces, such as IO and Collections . A using directive
that references a given namespace enables unqualified use of the types that are members of that namespace.
Because of the using directive, the program can use Console.WriteLine as shorthand for
System.Console.WriteLine .
The Hello class declared by the "Hello, World" program has a single member, the method named Main . The Main
method is declared with the static modifier. While instance methods can reference a particular enclosing object
instance using the keyword this , static methods operate without reference to a particular object. By convention, a
static method named Main serves as the entry point of a C# program.
The output of the program is produced by the WriteLine method of the Console class in the System namespace.
This class is provided by the standard class libraries, which, by default, are automatically referenced by the compiler.
C# programs use type declarations to create new types. A type declaration specifies the name and the members of
the new type. Five of C#'s categories of types are user-definable: class types, struct types, interface types, enum
types, and delegate types.
A class type defines a data structure that contains data members (fields) and function members (methods,
properties, and others). Class types support single inheritance and polymorphism, mechanisms whereby
derived classes can extend and specialize base classes.
A struct type is similar to a class type in that it represents a structure with data members and function
members. However, unlike classes, structs are value types and don't typically require heap allocation. Struct
types don't support user-specified inheritance, and all struct types implicitly inherit from type object .
An interface type defines a contract as a named set of public members. A class or struct that implements
an interface must provide implementations of the interface's members. An interface may inherit from
multiple base interfaces, and a class or struct may implement multiple interfaces.
A delegate type represents references to methods with a particular parameter list and return type. Delegates
make it possible to treat methods as entities that can be assigned to variables and passed as parameters.
Delegates are analogous to function types provided by functional languages. They're also similar to the concept
of function pointers found in some other languages. Unlike function pointers, delegates are object-oriented and
type-safe.
The class , struct , interface , and delegate types all support generics, whereby they can be parameterized with
other types.
C# supports single- and multi-dimensional arrays of any type. Unlike the types listed above, array types don't have
to be declared before they can be used. Instead, array types are constructed by following a type name with square
brackets. For example, int[] is a single-dimensional array of int , int[,] is a two-dimensional array of int ,
and int[][] is a single-dimensional array of single-dimensional array or "jagged" array of int .
Nullable types don't require a separate definition. For each non-nullable type T , there's a corresponding nullable
type T? , which can hold an additional value, null . For instance, int? is a type that can hold any 32-bit integer or
the value null , and string? is a type that can hold any string or the value null .
C#'s type system is unified such that a value of any type can be treated as an object . Every type in C# directly or
indirectly derives from the object class type, and object is the ultimate base class of all types. Values of reference
types are treated as objects simply by viewing the values as type object . Values of value types are treated as
objects by performing boxing and unboxing operations. In the following example, an int value is converted to
object and back again to int .
int i = 123;
object o = i; // Boxing
int j = (int)o; // Unboxing
When a value of a value type is assigned to an object reference, a "box" is allocated to hold the value. That box is
an instance of a reference type, and the value is copied into that box. Conversely, when an object reference is cast
to a value type, a check is made that the referenced object is a box of the correct value type. If the check succeeds,
the value in the box is copied to the value type.
C#'s unified type system effectively means that value types are treated as object references "on demand." Because
of the unification, general-purpose libraries that use type object can be used with all types that derive from
object , including both reference types and value types.
There are several kinds of variables in C#, including fields, array elements, local variables, and parameters. Variables
represent storage locations. Every variable has a type that determines what values can be stored in the variable, as
shown below.
Non-nullable value type
A value of that exact type
Nullable value type
A null value or a value of that exact type
object
A null reference, a reference to an object of any reference type, or a reference to a boxed value of any
value type
Class type
A null reference, a reference to an instance of that class type, or a reference to an instance of a class
derived from that class type
Interface type
A null reference, a reference to an instance of a class type that implements that interface type, or a
reference to a boxed value of a value type that implements that interface type
Array type
A null reference, a reference to an instance of that array type, or a reference to an instance of a
compatible array type
Delegate type
A null reference or a reference to an instance of a compatible delegate type
Program structure
The key organizational concepts in C# are programs , namespaces , types , members , and assemblies . Programs
declare types, which contain members and can be organized into namespaces. Classes, structs, and interfaces are
examples of types. Fields, methods, properties, and events are examples of members. When C# programs are
compiled, they're physically packaged into assemblies. Assemblies typically have the file extension .exe or .dll ,
depending on whether they implement applications or libraries , respectively.
As a small example, consider an assembly that contains the following code:
using System;
namespace Acme.Collections
{
public class Stack<T>
{
Entry _top;
public T Pop()
{
if (_top == null)
{
throw new InvalidOperationException();
}
T result = _top.Data;
_top = _top.Next;
return result;
}
class Entry
{
public Entry Next { get; set; }
public T Data { get; set; }
The fully qualified name of this class is Acme.Collections.Stack . The class contains several members: a field named
top , two methods named Push and Pop , and a nested class named Entry . The Entry class further contains
three members: a field named next , a field named data , and a constructor. The Stack is a generic class. It has
one type parameter, T that is replaced with a concrete type when it's used.
NOTE
A stack is a "first in - last out" (FILO) collection. New elements are added to the top of the stack. When an element is
removed, it is removed from the top of the stack.
Assemblies contain executable code in the form of Intermediate Language (IL) instructions, and symbolic
information in the form of metadata. Before it's executed, the Just-In-Time (JIT) compiler of .NET Common
Language Runtime converts the IL code in an assembly to processor-specific code.
Because an assembly is a self-describing unit of functionality containing both code and metadata, there's no need
for #include directives and header files in C#. The public types and members contained in a particular assembly
are made available in a C# program simply by referencing that assembly when compiling the program. For
example, this program uses the Acme.Collections.Stack class from the acme.dll assembly:
using System;
using Acme.Collections;
class Example
{
public static void Main()
{
var s = new Stack<int>();
s.Push(1); // stack contains 1
s.Push(10); // stack contains 1, 10
s.Push(100); // stack contains 1, 10, 100
Console.WriteLine(s.Pop()); // stack contains 1, 10
Console.WriteLine(s.Pop()); // stack contains 1
Console.WriteLine(s.Pop()); // stack is empty
}
}
To compile this program, you would need to reference the assembly containing the stack class defined in the earlier
example.
C# programs can be stored in several source files. When a C# program is compiled, all of the source files are
processed together, and the source files can freely reference each other. Conceptually, it's as if all the source files
were concatenated into one large file before being processed. Forward declarations are never needed in C#
because, with few exceptions, declaration order is insignificant. C# doesn't limit a source file to declaring only one
public type nor does it require the name of the source file to match a type declared in the source file.
Further articles in this tour explain these organizational blocks.
NE XT
Types and members
9/3/2020 • 6 minutes to read • Edit Online
Instances of classes are created using the new operator, which allocates memory for a new instance, invokes a
constructor to initialize the instance, and returns a reference to the instance. The following statements create two
Point objects and store references to those objects in two variables:
The memory occupied by an object is automatically reclaimed when the object is no longer reachable. It's neither
necessary nor possible to explicitly deallocate objects in C#.
Type parameters
Generic classes define type parameters . Type parameters are a list of type parameter names enclosed in angle
brackets. Type parameters follow the class name. The type parameters can then be used in the body of the class
declarations to define the members of the class. In the following example, the type parameters of Pair are
TFirst and TSecond :
public class Pair<TFirst, TSecond>
{
public TFirst First { get; }
public TSecond Second { get; }
A class type that is declared to take type parameters is called a generic class type. Struct, interface, and delegate
types can also be generic. When the generic class is used, type arguments must be provided for each of the type
parameters:
A generic type with type arguments provided, like Pair<int,string> above, is called a constructed type.
Base classes
A class declaration may specify a base class. Follow the class name and type parameters with a colon and the name
of the base class. Omitting a base class specification is the same as deriving from type object . In the following
example, the base class of Point3D is Point . From the first example, the base class of Point is object :
A class inherits the members of its base class. Inheritance means that a class implicitly contains almost all
members of its base class. A class doesn't inherit the instance and static constructors, and the finalizer. A derived
class can add new members to those members it inherits, but it can't remove the definition of an inherited
member. In the previous example, Point3D inherits the X and Y members from Point , and every Point3D
instance contains three properties, X , Y , and Z .
An implicit conversion exists from a class type to any of its base class types. A variable of a class type can reference
an instance of that class or an instance of any derived class. For example, given the previous class declarations, a
variable of type Point can reference either a Point or a Point3D :
Structs
Classes define types that support inheritance and polymorphism. They enable you to create sophisticated
behaviors based on hierarchies of derived classes. By contrast, struct types are simpler types whose primary
purpose is to store data values. Structs can't declare a base type; they implicitly derive from System.ValueType. You
can't derive other struct types from a struct type. They're implicitly sealed.
public struct Point
{
public double X { get; }
public double Y { get; }
Interfaces
An interface defines a contract that can be implemented by classes and structs. An interface can contain methods,
properties, events, and indexers. An interface typically doesn't provide implementations of the members it defines
—it merely specifies the members that must be supplied by classes or structs that implement the interface.
Interfaces may employ multiple inheritance . In the following example, the interface IComboBox inherits from
both ITextBox and IListBox .
interface IControl
{
void Paint();
}
Classes and structs can implement multiple interfaces. In the following example, the class EditBox implements
both IControl and IDataBound .
interface IDataBound
{
void Bind(Binder b);
}
When a class or struct implements a particular interface, instances of that class or struct can be implicitly
converted to that interface type. For example
Enums
An Enum type defines a set of constant values. The following enum declares constants that define different root
vegetables:
You can also define an enum to be used in combination as flags. The following declaration declares a set of flags
for the four seasons. Any combination of the seasons may be applied, including an All value that includes all
seasons:
[Flags]
public enum Seasons
{
None = 0,
Summer = 1,
Autumn = 2,
Winter = 4,
Spring = 8,
All = Summer | Autumn | Winter | Spring
}
Nullable types
Variables of any type may be declared as non-nullable or nullable . A nullable variable can hold an additional
null value, indicating no value. Nullable Value types (structs or enums) are represented by System.Nullable<T>.
Non-nullable and Nullable Reference types are both represented by the underlying reference type. The distinction
is represented by metadata read by the compiler and some libraries. The compiler provides warnings when
nullable references are dereferenced without first checking their value against null . The compiler also provides
warnings when non-nullable references are assigned a value that may be null . The following example declares a
nullable int , initializing it to null . Then, it sets the value to 5 . It demonstrates the same concept with a nullable
string . For more information, see nullable value types and nullable reference types.
Tuples
C# supports tuples , which provides concise syntax to group multiple data elements in a lightweight data structure.
You instantiate a tuple by declaring the types and names of the members between ( and ) , as shown in the
following example:
(double Sum, int Count) t2 = (4.5, 3);
Console.WriteLine($"Sum of {t2.Count} elements is {t2.Sum}.");
// Output:
// Sum of 3 elements is 4.5.
Tuples provide an alternative for data structure with multiple members, without using the building blocks
described in the next article.
PR EVIO U S NE XT
Program building blocks
9/3/2020 • 23 minutes to read • Edit Online
The types described in the previous article are built using these building blocks: members , expressions , and
statements .
Members
The members of a class are either static members or instance members . Static members belong to classes,
and instance members belong to objects (instances of classes).
The following list provides an overview of the kinds of members a class can contain.
Constants : Constant values associated with the class
Fields : Variables that are associated of the class
Methods : Actions that can be performed by the class
Proper ties : Actions associated with reading and writing named properties of the class
Indexers : Actions associated with indexing instances of the class like an array
Events : Notifications that can be generated by the class
Operators : Conversions and expression operators supported by the class
Constructors : Actions required to initialize instances of the class or the class itself
Finalizers : Actions performed before instances of the class are permanently discarded
Types : Nested types declared by the class
Accessibility
Each member of a class has an associated accessibility, which controls the regions of program text that can access
the member. There are six possible forms of accessibility. The access modifiers are summarized below.
public : Access isn't limited.
private : Access is limited to this class.
protected : Access is limited to this class or classes derived from this class.
internal : Access is limited to the current assembly ( .exe or .dll ).
protected internal : Access is limited to this class, classes derived from this class, or classes within the same
assembly.
private protected : Access is limited to this class or classes derived from this type within the same assembly.
Fields
A field is a variable that is associated with a class or with an instance of a class.
A field declared with the static modifier defines a static field. A static field identifies exactly one storage location. No
matter how many instances of a class are created, there's only ever one copy of a static field.
A field declared without the static modifier defines an instance field. Every instance of a class contains a separate
copy of all the instance fields of that class.
In the following example, each instance of the Color class has a separate copy of the r , g , and b instance
fields, but there's only one copy of the Black , White , Red , Green , and Blue static fields:
public class Color
{
public static readonly Color Black = new Color(0, 0, 0);
public static readonly Color White = new Color(255, 255, 255);
public static readonly Color Red = new Color(255, 0, 0);
public static readonly Color Green = new Color(0, 255, 0);
public static readonly Color Blue = new Color(0, 0, 255);
As shown in the previous example, read-only fields may be declared with a readonly modifier. Assignment to a
read-only field can only occur as part of the field’s declaration or in a constructor in the same class.
Methods
A method is a member that implements a computation or action that can be performed by an object or class. Static
methods are accessed through the class. Instance methods are accessed through instances of the class.
Methods may have a list of parameters, which represent values or variable references passed to the method.
Methods have a return type, which specifies the type of the value computed and returned by the method. A
method’s return type is void if it doesn't return a value.
Like types, methods may also have a set of type parameters, for which type arguments must be specified when the
method is called. Unlike types, the type arguments can often be inferred from the arguments of a method call and
need not be explicitly given.
The signature of a method must be unique in the class in which the method is declared. The signature of a method
consists of the name of the method, the number of type parameters, and the number, modifiers, and types of its
parameters. The signature of a method doesn't include the return type.
When a method body is a single expression, the method can be defined using a compact expression format, as
shown in the following example:
Parameters
Parameters are used to pass values or variable references to methods. The parameters of a method get their actual
values from the arguments that are specified when the method is invoked. There are four kinds of parameters:
value parameters, reference parameters, output parameters, and parameter arrays.
A value parameter is used for passing input arguments. A value parameter corresponds to a local variable that gets
its initial value from the argument that was passed for the parameter. Modifications to a value parameter don't
affect the argument that was passed for the parameter.
Value parameters can be optional, by specifying a default value so that corresponding arguments can be omitted.
A reference parameter is used for passing arguments by reference. The argument passed for a reference parameter
must be a variable with a definite value. During execution of the method, the reference parameter represents the
same storage location as the argument variable. A reference parameter is declared with the ref modifier. The
following example shows the use of ref parameters.
An output parameter is used for passing arguments by reference. It's similar to a reference parameter, except that it
doesn't require that you explicitly assign a value to the caller-provided argument. An output parameter is declared
with the out modifier. The following example shows the use of out parameters using the syntax introduced in C#
7.
static void Divide(int x, int y, out int result, out int remainder)
{
result = x / y;
remainder = x % y;
}
A parameter array permits a variable number of arguments to be passed to a method. A parameter array is
declared with the params modifier. Only the last parameter of a method can be a parameter array, and the type of
a parameter array must be a single-dimensional array type. The Write and WriteLine methods of the
System.Console class are good examples of parameter array usage. They're declared as follows.
Within a method that uses a parameter array, the parameter array behaves exactly like a regular parameter of an
array type. However, in an invocation of a method with a parameter array, it's possible to pass either a single
argument of the parameter array type or any number of arguments of the element type of the parameter array. In
the latter case, an array instance is automatically created and initialized with the given arguments. This example
int x, y, z;
x = 3;
y = 4;
z = 5;
Console.WriteLine("x={0} y={1} z={2}", x, y, z);
class Squares
{
public static void WriteSquares()
{
int i = 0;
int j;
while (i < 10)
{
j = i * i;
Console.WriteLine($"{i} x {i} = {j}");
i = i + 1;
}
}
}
C# requires a local variable to be definitely assigned before its value can be obtained. For example, if the
declaration of the previous i didn't include an initial value, the compiler would report an error for the later
usages of i because i wouldn't be definitely assigned at those points in the program.
A method can use return statements to return control to its caller. In a method returning void , return
statements can't specify an expression. In a method returning non-void, return statements must include an
expression that computes the return value.
Static and instance methods
A method declared with a static modifier is a static method. A static method doesn't operate on a specific
instance and can only directly access static members.
A method declared without a static modifier is an instance method. An instance method operates on a specific
instance and can access both static and instance members. The instance on which an instance method was invoked
can be explicitly accessed as this . It's an error to refer to this in a static method.
The following Entity class has both static and instance members.
class Entity
{
static int s_nextSerialNo;
int _serialNo;
public Entity()
{
_serialNo = s_nextSerialNo++;
}
Each Entity instance contains a serial number (and presumably some other information that isn't shown here).
The Entity constructor (which is like an instance method) initializes the new instance with the next available serial
number. Because the constructor is an instance member, it's permitted to access both the _serialNo instance field
and the s_nextSerialNo static field.
The GetNextSerialNo and SetNextSerialNo static methods can access the s_nextSerialNo static field, but it would
be an error for them to directly access the _serialNo instance field.
The following example shows the use of the Entity class.
Entity.SetNextSerialNo(1000);
Entity e1 = new Entity();
Entity e2 = new Entity();
Console.WriteLine(e1.GetSerialNo()); // Outputs "1000"
Console.WriteLine(e2.GetSerialNo()); // Outputs "1001"
Console.WriteLine(Entity.GetNextSerialNo()); // Outputs "1002"
The SetNextSerialNo and GetNextSerialNo static methods are invoked on the class whereas the GetSerialNo
instance method is invoked on instances of the class.
Virtual, override, and abstract methods
When an instance method declaration includes a virtual modifier, the method is said to be a virtual method.
When no virtual modifier is present, the method is said to be a nonvirtual method.
When a virtual method is invoked, the run-time type of the instance for which that invocation takes place
determines the actual method implementation to invoke. In a nonvirtual method invocation, the compile-time type
of the instance is the determining factor.
A virtual method can be overridden in a derived class. When an instance method declaration includes an override
modifier, the method overrides an inherited virtual method with the same signature. A virtual method declaration
introduces a new method. An override method declaration specializes an existing inherited virtual method by
providing a new implementation of that method.
An abstract method is a virtual method with no implementation. An abstract method is declared with the abstract
modifier and is permitted only in an abstract class. An abstract method must be overridden in every non-abstract
derived class.
The following example declares an abstract class, Expression , which represents an expression tree node, and three
derived classes, Constant , VariableReference , and Operation , which implement expression tree nodes for
constants, variable references, and arithmetic operations. (This example is similar to, but not related to the
expression tree types).
public abstract class Expression
{
public abstract double Evaluate(Dictionary<string, object> vars);
}
The previous four classes can be used to model arithmetic expressions. For example, using instances of these
classes, the expression x + 3 can be represented as follows.
The Evaluate method of an Expression instance is invoked to evaluate the given expression and produce a
double value. The method takes a Dictionary argument that contains variable names (as keys of the entries) and
values (as values of the entries). Because Evaluate is an abstract method, non-abstract classes derived from
Expression must override Evaluate .
A Constant 's implementation of Evaluate simply returns the stored constant. A VariableReference 's
implementation looks up the variable name in the dictionary and returns the resulting value. An Operation 's
implementation first evaluates the left and right operands (by recursively invoking their Evaluate methods) and
then performs the given arithmetic operation.
The following program uses the Expression classes to evaluate the expression x * (y + 2) for different values of
x and y .
Method overloading
Method overloading permits multiple methods in the same class to have the same name as long as they have
unique signatures. When compiling an invocation of an overloaded method, the compiler uses overload resolution
to determine the specific method to invoke. Overload resolution finds the one method that best matches the
arguments. If no single best match can be found, an error is reported. The following example shows overload
resolution in effect. The comment for each invocation in the UsageExample method shows which method is
invoked.
class OverloadingExample
{
static void F() => Console.WriteLine("F()");
static void F(object x) => Console.WriteLine("F(object)");
static void F(int x) => Console.WriteLine("F(int)");
static void F(double x) => Console.WriteLine("F(double)");
static void F<T>(T x) => Console.WriteLine("F<T>(T)");
static void F(double x, double y) => Console.WriteLine("F(double, double)");
As shown by the example, a particular method can always be selected by explicitly casting the arguments to the
exact parameter types and type arguments.
T[] _items;
int _count;
Constructors
C# supports both instance and static constructors. An instance constructor is a member that implements the
actions required to initialize an instance of a class. A static constructor is a member that implements the actions
required to initialize a class itself when it's first loaded.
A constructor is declared like a method with no return type and the same name as the containing class. If a
constructor declaration includes a static modifier, it declares a static constructor. Otherwise, it declares an
instance constructor.
Instance constructors can be overloaded and can have optional parameters. For example, the MyList<T> class
declares one instance constructor with a single optional int parameter. Instance constructors are invoked using
the new operator. The following statements allocate two MyList<string> instances using the constructor of the
MyList class with and without the optional argument.
Similar to fields and methods, C# supports both instance properties and static properties. Static properties are
declared with the static modifier, and instance properties are declared without it.
The accessor(s) of a property can be virtual. When a property declaration includes a virtual , abstract , or
override modifier, it applies to the accessor(s) of the property.
Indexers
An indexer is a member that enables objects to be indexed in the same way as an array. An indexer is declared like
a property except that the name of the member is this followed by a parameter list written between the
delimiters [ and ] . The parameters are available in the accessor(s) of the indexer. Similar to properties, indexers
can be read-write, read-only, and write-only, and the accessor(s) of an indexer can be virtual.
The MyList<T> class declares a single read-write indexer that takes an int parameter. The indexer makes it
possible to index MyList<T> instances with int values. For example:
Indexers can be overloaded. A class can declare multiple indexers as long as the number or types of their
parameters differ.
Events
An event is a member that enables a class or object to provide notifications. An event is declared like a field except
that the declaration includes an event keyword and the type must be a delegate type.
Within a class that declares an event member, the event behaves just like a field of a delegate type (provided the
event isn't abstract and doesn't declare accessors). The field stores a reference to a delegate that represents the
event handlers that have been added to the event. If no event handlers are present, the field is null .
The MyList<T> class declares a single event member called Changed , which indicates that a new item has been
added to the list. The Changed event is raised by the OnChanged virtual method, which first checks whether the
event is null (meaning that no handlers are present). The notion of raising an event is precisely equivalent to
invoking the delegate represented by the event. There are no special language constructs for raising events.
Clients react to events through event handlers. Event handlers are attached using the += operator and removed
using the -= operator. The following example attaches an event handler to the Changed event of a
MyList<string> .
class EventExample
{
static int s_changeCount;
For advanced scenarios where control of the underlying storage of an event is desired, an event declaration can
explicitly provide add and remove accessors, which are similar to the set accessor of a property.
Operators
An operator is a member that defines the meaning of applying a particular expression operator to instances of a
class. Three kinds of operators can be defined: unary operators, binary operators, and conversion operators. All
operators must be declared as public and static .
The MyList<T> class declares two operators, operator == and operator != . These overridden operators give new
meaning to expressions that apply those operators to MyList instances. Specifically, the operators define equality
of two MyList<T> instances as comparing each of the contained objects using their Equals methods. The
following example uses the == operator to compare two MyList<int> instances.
Finalizers
A finalizer is a member that implements the actions required to finalize an instance of a class. Typically, a finalizer is
needed to release unmanaged resources. Finalizers can't have parameters, they can't have accessibility modifiers,
and they can't be invoked explicitly. The finalizer for an instance is invoked automatically during garbage collection.
For more details, see the article on finalizers.
The garbage collector is allowed wide latitude in deciding when to collect objects and run finalizers. Specifically, the
timing of finalizer invocations isn't deterministic, and finalizers may be executed on any thread. For these and other
reasons, classes should implement finalizers only when no other solutions are feasible.
The using statement provides a better approach to object destruction.
Expressions
Expressions are constructed from operands and operators. The operators of an expression indicate which
operations to apply to the operands. Examples of operators include + , - , * , / , and new . Examples of operands
include literals, fields, local variables, and expressions.
When an expression contains multiple operators, the precedence of the operators controls the order in which the
individual operators are evaluated. For example, the expression x + y * z is evaluated as x + (y * z) because
the * operator has higher precedence than the + operator.
When an operand occurs between two operators with the same precedence, the associativity of the operators
controls the order in which the operations are performed:
Except for the assignment and null-coalescing operators, all binary operators are left-associative, meaning that
operations are performed from left to right. For example, x + y + z is evaluated as (x + y) + z .
The assignment operators, the null-coalescing ?? and ??= operators, and the conditional operator ?: are
right-associative, meaning that operations are performed from right to left. For example, x = y = z is
evaluated as x = (y = z) .
Precedence and associativity can be controlled using parentheses. For example, x + y * z first multiplies y by z
and then adds the result to x , but (x + y) * z first adds x and y and then multiplies the result by z .
Most operators can be overloaded. Operator overloading permits user-defined operator implementations to be
specified for operations where one or both of the operands are of a user-defined class or struct type.
C# provides a number of operators to perform arithmetic, logical, bitwise and shift operations and equality and
order comparisons.
For the complete list of C# operators ordered by precedence level, see C# operators.
Statements
The actions of a program are expressed using statements. C# supports several different kinds of statements, a
number of which are defined in terms of embedded statements.
A block permits multiple statements to be written in contexts where a single statement is allowed. A block
consists of a list of statements written between the delimiters { and } .
Declaration statements are used to declare local variables and constants.
Expression statements are used to evaluate expressions. Expressions that can be used as statements include
method invocations, object allocations using the new operator, assignments using = and the compound
assignment operators, increment and decrement operations using the ++ and -- operators and await
expressions.
Selection statements are used to select one of a number of possible statements for execution based on the
value of some expression. This group contains the if and switch statements.
Iteration statements are used to execute repeatedly an embedded statement. This group contains the while ,
do , for , and foreach statements.
Jump statements are used to transfer control. This group contains the break , continue , goto , throw , return ,
and yield statements.
The try ... catch statement is used to catch exceptions that occur during execution of a block, and the try ...
finally statement is used to specify finalization code that is always executed, whether an exception occurred
or not.
The checked and unchecked statements are used to control the overflow-checking context for integral-type
arithmetic operations and conversions.
The lock statement is used to obtain the mutual-exclusion lock for a given object, execute a statement, and
then release the lock.
The using statement is used to obtain a resource, execute a statement, and then dispose of that resource.
The following lists the kinds of statements that can be used:
Local variable declaration.
Local constant declaration.
Expression statement.
if statement.
switch statement.
while statement.
do statement.
for statement.
foreach statement.
break statement.
continue statement.
goto statement.
return statement.
yield statement.
throw statements and try statements.
checked and unchecked statements.
lock statement.
using statement.
PR EVIO U S NE XT
Major language areas
9/3/2020 • 9 minutes to read • Edit Online
This example creates and operates on a single-dimensional array . C# also supports multi-dimensional
arrays . The number of dimensions of an array type, also known as the rank of the array type, is one plus the
number of commas written between the square brackets of the array type. The following example allocates a
single-dimensional, a two-dimensional, and a three-dimensional array, respectively.
The a1 array contains 10 elements, the a2 array contains 50 (10 × 5) elements, and the a3 array contains 100
(10 × 5 × 2) elements. The element type of an array can be any type, including an array type. An array with
elements of an array type is sometimes called a jagged array because the lengths of the element arrays don't all
have to be the same. The following example allocates an array of arrays of int :
int[][] a = new int[3][];
a[0] = new int[10];
a[1] = new int[5];
a[2] = new int[20];
The first line creates an array with three elements, each of type int[] and each with an initial value of null . The
next lines then initialize the three elements with references to individual array instances of varying lengths.
The new operator permits the initial values of the array elements to be specified using an array initializer , which
is a list of expressions written between the delimiters { and } . The following example allocates and initializes an
int[] with three elements.
The length of the array is inferred from the number of expressions between { and } . Local variable and field
declarations can be shortened further such that the array type doesn't have to be restated.
int[] a = { 1, 2, 3 };
The foreach statement can be used to enumerate the elements of any collection. The following code enumerates
the array from the preceding example:
The foreach statement uses the IEnumerable<T> interface, so can work with any collection.
String interpolation
C# string interpolation enables you to format strings by defining expressions whose results are placed in a
format string. For example, the following example prints the temperature on a given day from a set of weather
data:
An interpolated string is declared using the $ token. String interpolation evaluates the expressions between {
and } , then converts the result to a string , and replaces the text between the brackets with the string result of
the expression. The : in the first expression, {weatherData.Date:MM-DD-YYYY} specifies the format string. In the
preceding example, it specifies that the date should be printed in "MM-DD-YYYY" format.
Pattern matching
The C# language provides pattern matching expressions to query the state of an object and execute code based
on that state. You can inspect types and the values of properties and fields to determine which action to take. The
switch expression is the primary expression for pattern matching.
class Multiplier
{
double _factor;
class DelegateExample
{
static double[] Apply(double[] a, Function f)
{
var result = new double[a.Length];
for (int i = 0; i < a.Length; i++) result[i] = f(a[i]);
return result;
}
An instance of the Function delegate type can reference any method that takes a double argument and returns a
double value. The Apply method applies a given Function to the elements of a double[] , returning a double[]
with the results. In the Main method, Apply is used to apply three different functions to a double[] .
A delegate can reference either a static method (such as Square or Math.Sin in the previous example) or an
instance method (such as m.Multiply in the previous example). A delegate that references an instance method also
references a particular object, and when the instance method is invoked through the delegate, that object becomes
this in the invocation.
Delegates can also be created using anonymous functions, which are "inline methods" that are created when
declared. Anonymous functions can see the local variables of the surrounding methods. The following example
doesn't create a class:
async / await
C# supports asynchronous programs with two keywords: async and await . You add the async modifier to a
method declaration to declare the method is asynchronous. The await operator tells the compiler to
asynchronously await for a result to finish. Control is returned to the caller, and the method returns a structure that
manages the state of the asynchronous work. The structure is typically a System.Threading.Tasks.Task<TResult>,
but can be any type that supports the awaiter pattern. These features enable you to write code that reads as its
synchronous counterpart, but executes asynchronously. For example, the following code downloads the home page
for Microsoft docs:
This small sample shows the major features for asynchronous programming:
The method declaration includes the async modifier.
The body of the method await s the return of the GetByteArrayAsync method.
The type specified in the return statement matches the type argument in the Task<T> declaration for the
method. (A method that returns a Task would use return statements without any argument).
Attributes
Types, members, and other entities in a C# program support modifiers that control certain aspects of their
behavior. For example, the accessibility of a method is controlled using the public , protected , internal , and
private modifiers. C# generalizes this capability such that user-defined types of declarative information can be
attached to program entities and retrieved at run-time. Programs specify this additional declarative information by
defining and using attributes .
The following example declares a HelpAttribute attribute that can be placed on program entities to provide links
to their associated documentation.
All attribute classes derive from the Attribute base class provided by the .NET library. Attributes can be applied by
giving their name, along with any arguments, inside square brackets just before the associated declaration. If an
attribute’s name ends in Attribute , that part of the name can be omitted when the attribute is referenced. For
example, the HelpAttribute can be used as follows.
[Help("https://docs.microsoft.com/dotnet/csharp/tour-of-csharp/features")]
public class Widget
{
[Help("https://docs.microsoft.com/dotnet/csharp/tour-of-csharp/features",
Topic = "Display")]
public void Display(string text) { }
}
This example attaches a HelpAttribute to the Widget class. It adds another HelpAttribute to the Display method
in the class. The public constructors of an attribute class control the information that must be provided when the
attribute is attached to a program entity. Additional information can be provided by referencing public read-write
properties of the attribute class (such as the reference to the Topic property previously).
The metadata defined by attributes can be read and manipulated at runtime using reflection. When a particular
attribute is requested using this technique, the constructor for the attribute class is invoked with the information
provided in the program source, and the resulting attribute instance is returned. If additional information was
provided through properties, those properties are set to the given values before the attribute instance is returned.
The following code sample demonstrates how to get the HelpAttribute instances associated to the Widget class
and its Display method.
if (widgetClassAttributes.Length > 0)
{
HelpAttribute attr = (HelpAttribute)widgetClassAttributes[0];
Console.WriteLine($"Widget class help URL : {attr.Url} - Related topic : {attr.Topic}");
}
if (displayMethodAttributes.Length > 0)
{
HelpAttribute attr = (HelpAttribute)displayMethodAttributes[0];
Console.WriteLine($"Display method help URL : {attr.Url} - Related topic : {attr.Topic}");
}
Learn more
You can explore more about C# by trying one of our tutorials.
PR EVIO U S
What's new in C# 8.0
9/3/2020 • 16 minutes to read • Edit Online
Readonly members
You can apply the readonly modifier to members of a struct. It indicates that the member doesn't modify state. It's
more granular than applying the readonly modifier to a struct declaration. Consider the following mutable
struct:
public struct Point
{
public double X { get; set; }
public double Y { get; set; }
public double Distance => Math.Sqrt(X * X + Y * Y);
Like most structs, the ToString() method doesn't modify state. You could indicate that by adding the readonly
modifier to the declaration of ToString() :
The preceding change generates a compiler warning, because ToString accesses the Distance property, which
isn't marked readonly :
warning CS8656: Call to non-readonly member 'Point.Distance.get' from a 'readonly' member results in an
implicit copy of 'this'
The compiler warns you when it needs to create a defensive copy. The Distance property doesn't change state, so
you can fix this warning by adding the readonly modifier to the declaration:
Notice that the readonly modifier is necessary on a read-only property. The compiler doesn't assume get
accessors don't modify state; you must declare readonly explicitly. Auto-implemented properties are an exception;
the compiler will treat all auto-implemented getters as readonly , so here there's no need to add the readonly
modifier to the X and Y properties.
The compiler does enforce the rule that readonly members don't modify state. The following method won't
compile unless you remove the readonly modifier:
This feature lets you specify your design intent so the compiler can enforce it, and make optimizations based on
that intent.
For more information, see the readonly instance members section of the Structure types article.
If your application defined an RGBColor type that is constructed from the R , G and B components, you could
convert a Rainbow value to its RGB values using the following method containing a switch expression:
Property patterns
The proper ty pattern enables you to match on properties of the object examined. Consider an eCommerce site
that must compute sales tax based on the buyer's address. That computation isn't a core responsibility of an
Address class. It will change over time, likely more often than address format changes. The amount of sales tax
depends on the State property of the address. The following method uses the property pattern to compute the
sales tax from the address and the price:
The messages indicate the winner. The discard case represents the three combinations for ties, or other text inputs.
Positional patterns
Some types include a Deconstruct method that deconstructs its properties into discrete variables. When a
Deconstruct method is accessible, you can use positional patterns to inspect properties of the object and use
those properties for a pattern. Consider the following Point class that includes a Deconstruct method to create
discrete variables for X and Y :
Additionally, consider the following enum that represents various positions of a quadrant:
The following method uses the positional pattern to extract the values of x and y . Then, it uses a when clause
to determine the Quadrant of the point:
The discard pattern in the preceding switch matches when either x or y is 0, but not both. A switch expression
must either produce a value or throw an exception. If none of the cases match, the switch expression throws an
exception. The compiler generates a warning for you if you don't cover all possible cases in your switch expression.
You can explore pattern matching techniques in this advanced tutorial on pattern matching.
Using declarations
A using declaration is a variable declaration preceded by the using keyword. It tells the compiler that the
variable being declared should be disposed at the end of the enclosing scope. For example, consider the following
code that writes a text file:
In the preceding example, the file is disposed when the closing brace for the method is reached. That's the end of
the scope in which file is declared. The preceding code is equivalent to the following code that uses the classic
using statement:
In the preceding example, the file is disposed when the closing brace associated with the using statement is
reached.
In both cases, the compiler generates the call to Dispose() . The compiler generates an error if the expression in the
using statement isn't disposable.
int M()
{
int y;
LocalFunction();
return y;
The following code contains a static local function. It can be static because it doesn't access any variables in the
enclosing scope:
int M()
{
int y = 5;
int x = 7;
return Add(x, y);
Asynchronous streams
Starting with C# 8.0, you can create and consume streams asynchronously. A method that returns an asynchronous
stream has three properties:
1. It's declared with the async modifier.
2. It returns an IAsyncEnumerable<T>.
3. The method contains yield return statements to return successive elements in the asynchronous stream.
Consuming an asynchronous stream requires you to add the await keyword before the foreach keyword when
you enumerate the elements of the stream. Adding the await keyword requires the method that enumerates the
asynchronous stream to be declared with the async modifier and to return a type allowed for an async method.
Typically that means returning a Task or Task<TResult>. It can also be a ValueTask or ValueTask<TResult>. A method
can both consume and produce an asynchronous stream, which means it would return an IAsyncEnumerable<T>.
The following code generates a sequence from 0 to 19, waiting 100 ms between generating each number:
You would enumerate the sequence using the await foreach statement:
You can try asynchronous streams yourself in our tutorial on creating and consuming async streams. By default,
stream elements are processed in the captured context. If you want to disable capturing of the context, use the
TaskAsyncEnumerableExtensions.ConfigureAwait extension method. For more information about synchronization
contexts and capturing the current context, see the article on consuming the Task-based asynchronous pattern.
Asynchronous disposable
Starting with C# 8.0, the language supports asynchronous disposable types that implement the
System.IAsyncDisposable interface. You use the await using statement to work with an asynchronously disposable
object. For more information, see the Implement a DisposeAsync method article.
A range specifies the start and end of a range. The start of the range is inclusive, but the end of the range is
exclusive, meaning the start is included in the range but the end isn't included in the range. The range [0..^0]
represents the entire range, just as [0..sequence.Length] represents the entire range.
Let's look at a few examples. Consider the following array, annotated with its index from the start and from the end:
The following code creates a subrange with the words "quick", "brown", and "fox". It includes words[1] through
words[3] . The element words[4] isn't in the range.
The following code creates a subrange with "lazy" and "dog". It includes words[^2] and words[^1] . The end index
words[^0] isn't included:
The following examples create ranges that are open ended for the start, end, or both:
Null-coalescing assignment
C# 8.0 introduces the null-coalescing assignment operator ??= . You can use the ??= operator to assign the value
of its right-hand operand to its left-hand operand only if the left-hand operand evaluates to null .
the Coords<int> type is an unmanaged type in C# 8.0 and later. Like for any unmanaged type, you can create a
pointer to a variable of this type or allocate a block of memory on the stack for instances of this type:
There are two main themes to the C# 7.3 release. One theme provides features that enable safe code to be as
performant as unsafe code. The second theme provides incremental improvements to existing features. In addition,
new compiler options were added in this release.
The following new features support the theme of better performance for safe code:
You can access fixed fields without pinning.
You can reassign ref local variables.
You can use initializers on stackalloc arrays.
You can use fixed statements with any type that supports a pattern.
You can use additional generic constraints.
The following enhancements were made to existing features:
You can test == and != with tuple types.
You can use expression variables in more locations.
You may attach attributes to the backing field of auto-implemented properties.
Method resolution when arguments differ by in has been improved.
Overload resolution now has fewer ambiguous cases.
The new compiler options are:
-publicsign to enable Open Source Software (OSS) signing of assemblies.
-pathmap to provide a mapping for source directories.
The remainder of this article provides details and links to learn more about each of the improvements. You can
explore these features in your environment using the dotnet try global tool:
1. Install the dotnet-try global tool.
2. Clone the dotnet/try-samples repository.
3. Set the current directory to the csharp7 subdirectory for the try-samples repository.
4. Run dotnet try .
unsafe struct S
{
public fixed int myFixedField[10];
}
In earlier versions of C#, you needed to pin a variable to access one of the integers that are part of myFixedField .
Now, the following code compiles without pinning the variable p inside a separate fixed statement:
class C
{
static S s = new S();
The variable p accesses one element in myFixedField . You don't need to declare a separate int* variable. Note
that you still need an unsafe context. In earlier versions of C#, you need to declare a second fixed pointer:
class C
{
static S s = new S();
For more information, see the article on ref returns and ref locals, and the article on foreach .
stackalloc arrays support initializers
You've been able to specify the values for elements in an array when you initialize it:
Now, that same syntax can be applied to arrays that are declared with stackalloc :
The C# tuple types now support == and != . For more information, see the Tuple equality section of the Tuple
types article.
Attach attributes to the backing fields for auto -implemented properties
This syntax is now supported:
[field: SomeThingAboutFieldAttribute]
public int SomeProperty { get; set; }
The attribute SomeThingAboutFieldAttribute is applied to the compiler generated backing field for SomeProperty .
For more information, see attributes in the C# programming guide.
in method overload resolution tiebreaker
When the in argument modifier was added, these two methods would cause an ambiguity:
Now, the by value (first in the preceding example) overload is better than the by readonly reference version. To call
the version with the readonly reference argument, you must include the in modifier when calling the method.
NOTE
This was implemented as a bug fix. This no longer is ambiguous even with the language version set to "7.2".
public class D : B
{
public D(int i) : base(i, out var j)
{
Console.WriteLine($"The value of 'j' is {j}");
}
}
C# 7.2 is another point release that adds a number of useful features. One theme for this release is working more
efficiently with value types by avoiding unnecessary copies or allocations.
The remaining features are small, nice-to-have features.
C# 7.2 uses the language version selection configuration element to select the compiler language version.
The new language features in this release are:
Techniques for writing safe efficient code
A combination of syntax improvements that enable working with value types using reference semantics.
Non-trailing named arguments
Named arguments can be followed by positional arguments.
Leading underscores in numeric literals
Numeric literals can now have leading underscores before any printed digits.
private protected access modifier
The private protected access modifier enables access for derived classes in the same assembly.
Conditional ref expressions
The result of a conditional expression ( ?: ) can now be a reference.
The remainder of this article provides an overview of each feature. For each feature, you'll learn the reasoning
behind it. You'll learn the syntax. You can explore these features in your environment using the dotnet try global
tool:
1. Install the dotnet-try global tool.
2. Clone the dotnet/try-samples repository.
3. Set the current directory to the csharp7 subdirectory for the try-samples repository.
4. Run dotnet try .
You can read more about all these changes in Write safe efficient code.
C# 7.1 is the first point release to the C# language. It marks an increased release cadence for the language. You can
use the new features sooner, ideally when each new feature is ready. C# 7.1 adds the ability to configure the
compiler to match a specified version of the language. That enables you to separate the decision to upgrade tools
from the decision to upgrade language versions.
C# 7.1 adds the language version selection configuration element, three new language features, and new compiler
behavior.
The new language features in this release are:
async Main method
The entry point for an application can have the async modifier.
default literal expressions
You can use default literal expressions in default value expressions when the target type can be inferred.
Inferred tuple element names
The names of tuple elements can be inferred from tuple initialization in many cases.
Pattern matching on generic type parameters
You can use pattern match expressions on variables whose type is a generic type parameter.
Finally, the compiler has two options -refout and -refonly that control reference assembly generation.
To use the latest features in a point release, you need to configure the compiler language version and select the
version.
The remainder of this article provides an overview of each feature. For each feature, you'll learn the reasoning
behind it. You'll learn the syntax. You can explore these features in your environment using the dotnet try global
tool:
1. Install the dotnet-try global tool.
2. Clone the dotnet/try-samples repository.
3. Set the current directory to the csharp7 subdirectory for the try-samples repository.
4. Run dotnet try .
Async main
An async main method enables you to use await in your Main method. Previously you would need to write:
If your program doesn't return an exit code, you can declare a Main method that returns a Task:
You can read more about the details in the async main article in the programming guide.
You can now omit the type on the right-hand side of the initialization:
For more information, see the default literal section of the default operator article.
int count = 5;
string label = "Colors used in the map";
var pair = (count: count, label: label);
The names of tuple elements can be inferred from the variables used to initialize the tuple in C# 7.1:
int count = 5;
string label = "Colors used in the map";
var pair = (count, label); // element names are "count" and "label"
You can learn more about this feature in the Tuple types article.
out variables
The existing syntax that supports out parameters has been improved in this version. You can now declare out
variables in the argument list of a method call, rather than writing a separate declaration statement:
if (int.TryParse(input, out int result))
Console.WriteLine(result);
else
Console.WriteLine("Could not parse input");
You may want to specify the type of the out variable for clarity, as shown above. However, the language does
support using an implicitly typed local variable:
Tuples
C# provides a rich syntax for classes and structs that is used to explain your design intent. But sometimes that rich
syntax requires extra work with minimal benefit. You may often write methods that need a simple structure
containing more than one data element. To support these scenarios tuples were added to C#. Tuples are lightweight
data structures that contain multiple fields to represent the data members. The fields aren't validated, and you can't
define your own methods
NOTE
Tuples were available before C# 7.0, but they were inefficient and had no language support. This meant that tuple elements
could only be referenced as Item1 , Item2 and so on. C# 7.0 introduces language support for tuples, which enables
semantic names for the fields of a tuple using new, more efficient tuple types.
You can create a tuple by assigning a value to each member, and optionally providing semantic names to each of
the members of the tuple:
The namedLetters tuple contains fields referred to as Alpha and Beta . Those names exist only at compile time and
aren't preserved, for example when inspecting the tuple using reflection at run time.
In a tuple assignment, you can also specify the names of the fields on the right-hand side of the assignment:
There may be times when you want to unpackage the members of a tuple that were returned from a method. You
can do that by declaring separate variables for each of the values in the tuple. This unpackaging is called
deconstructing the tuple:
(int max, int min) = Range(numbers);
Console.WriteLine(max);
Console.WriteLine(min);
You can also provide a similar deconstruction for any type in .NET. You write a Deconstruct method as a member of
the class. That Deconstruct method provides a set of out arguments for each of the properties you want to
extract. Consider this Point class that provides a deconstructor method that extracts the X and Y coordinates:
Discards
Often when deconstructing a tuple or calling a method with out parameters, you're forced to define a variable
whose value you don't care about and don't intend to use. C# adds support for discards to handle this scenario. A
discard is a write-only variable whose name is _ (the underscore character); you can assign all of the values that
you intend to discard to the single variable. A discard is like an unassigned variable; apart from the assignment
statement, the discard can't be used in code.
Discards are supported in the following scenarios:
When deconstructing tuples or user-defined types.
When calling methods with out parameters.
In a pattern matching operation with the is and switch statements.
As a standalone identifier when you want to explicitly identify the value of an assignment as a discard.
The following example defines a QueryCityDataForYears method that returns a 6-tuple that contains data for a city
for two different years. The method call in the example is concerned only with the two population values returned
by the method and so treats the remaining values in the tuple as discards when it deconstructs the tuple.
using System;
using System.Collections.Generic;
private static (string, double, int, int, int, int) QueryCityDataForYears(string name, int year1, int
year2)
{
int population1 = 0, population2 = 0;
double area = 0;
Pattern matching
Pattern matching is a feature that allows you to implement method dispatch on properties other than the type of an
object. You're probably already familiar with method dispatch based on the type of an object. In object-oriented
programming, virtual and override methods provide language syntax to implement method dispatching based on
an object's type. Base and Derived classes provide different implementations. Pattern matching expressions extend
this concept so that you can easily implement similar dispatch patterns for types and data elements that aren't
related through an inheritance hierarchy.
Pattern matching supports is expressions and switch expressions. Each enables inspecting an object and its
properties to determine if that object satisfies the sought pattern. You use the when keyword to specify additional
rules to the pattern.
The is pattern expression extends the familiar is operator to query an object about its type and assign the result
in one instruction. The following code checks if a variable is an int , and if so, adds it to the current sum:
The preceding small example demonstrates the enhancements to the is expression. You can test against value
types as well as reference types, and you can assign the successful result to a new variable of the correct type.
The switch match expression has a familiar syntax, based on the switch statement already part of the C# language.
The updated switch statement has several new constructs:
The governing type of a switch expression is no longer restricted to integral types, Enum types, string , or a
nullable type corresponding to one of those types. Any type may be used.
You can test the type of the switch expression in each case label. As with the is expression, you may assign a
new variable to that type.
You may add a when clause to further test conditions on that variable.
The order of case labels is now important. The first branch to match is executed; others are skipped.
You can learn more about pattern matching in Pattern Matching in C#.
You can declare the return value as a ref and modify that value in the matrix, as shown in the following code:
The C# language has several rules that protect you from misusing the ref locals and returns:
You must add the ref keyword to the method signature and to all return statements in a method.
That makes it clear the method returns by reference throughout the method.
A ref return may be assigned to a value variable, or a ref variable.
The caller controls whether the return value is copied or not. Omitting the ref modifier when assigning
the return value indicates that the caller wants a copy of the value, not a reference to the storage.
You can't assign a standard method return value to a ref local variable.
That disallows statements like ref int i = sequence.Count();
You can't return a ref to a variable whose lifetime doesn't extend beyond the execution of the method.
That means you can't return a reference to a local variable or a variable with a similar scope.
ref locals and returns can't be used with async methods.
The compiler can't know if the referenced variable has been set to its final value when the async method
returns.
The addition of ref locals and ref returns enables algorithms that are more efficient by avoiding copying values, or
performing dereferencing operations multiple times.
Adding ref to the return value is a source compatible change. Existing code compiles, but the ref return value is
copied when assigned. Callers must update the storage for the return value to a ref local variable to store the
return as a reference.
For more information, see the ref keyword article.
Local functions
Many designs for classes include methods that are called from only one location. These additional private methods
keep each method small and focused. Local functions enable you to declare methods inside the context of another
method. Local functions make it easier for readers of the class to see that the local method is only called from the
context in which it is declared.
There are two common use cases for local functions: public iterator methods and public async methods. Both types
of methods generate code that reports errors later than programmers might expect. In iterator methods, any
exceptions are observed only when calling code that enumerates the returned sequence. In async methods, any
exceptions are only observed when the returned Task is awaited. The following example demonstrates separating
parameter validation from the iterator implementation using a local function:
public static IEnumerable<char> AlphabetSubset3(char start, char end)
{
if (start < 'a' || start > 'z')
throw new ArgumentOutOfRangeException(paramName: nameof(start), message: "start must be a letter");
if (end < 'a' || end > 'z')
throw new ArgumentOutOfRangeException(paramName: nameof(end), message: "end must be a letter");
return alphabetSubsetImplementation();
IEnumerable<char> alphabetSubsetImplementation()
{
for (var c = start; c < end; c++)
yield return c;
}
}
The same technique can be employed with async methods to ensure that exceptions arising from argument
validation are thrown before the asynchronous work begins:
return longRunningWorkImplementation();
NOTE
Some of the designs that are supported by local functions can also be accomplished using lambda expressions. For more
information, see Local functions vs. lambda expressions.
// Expression-bodied finalizer
~ExpressionMembersExample() => Console.Error.WriteLine("Finalized!");
NOTE
This example does not need a finalizer, but it is shown to demonstrate the syntax. You should not implement a finalizer in
your class unless it is necessary to release unmanaged resources. You should also consider using the SafeHandle class instead
of managing unmanaged resources directly.
These new locations for expression-bodied members represent an important milestone for the C# language: These
features were implemented by community members working on the open-source Roslyn project.
Changing a method to an expression bodied member is a binary compatible change.
Throw expressions
In C#, throw has always been a statement. Because throw is a statement, not an expression, there were C#
constructs where you couldn't use it. These included conditional expressions, null coalescing expressions, and some
lambda expressions. The addition of expression-bodied members adds more locations where throw expressions
would be useful. So that you can write any of these constructs, C# 7.0 introduces throw expressions.
This addition makes it easier to write more expression-based code. You don't need additional statements for error
checking.
This enhancement is most useful for library authors to avoid allocating a Task in performance critical code.
The 0b at the beginning of the constant indicates that the number is written as a binary number. Binary numbers
can get long, so it's often easier to see the bit patterns by introducing the _ as a digit separator, as shown above in
the binary constant. The digit separator can appear anywhere in the constant. For base 10 numbers, it is common
to use it as a thousands separator:
The digit separator can be used with decimal , float , and double types as well:
Taken together, you can declare numeric constants with much more readability.
What's New in C# 6
8/13/2019 • 9 minutes to read • Edit Online
The 6.0 release of C# contained many features that improve productivity for developers. The overall effect of these
features is that you write more concise code that is also more readable. The syntax contains less ceremony for
many common practices. It's easier to see the design intent with less ceremony. Learn these features well, and you'll
be more productive and write more readable code. You can concentrate more on your features than on the
constructs of the language.
The rest of this article provides an overview of each of these features, with a link to explore each feature. You can
also explore the features in an interactive exploration on C# 6 in the tutorials section.
Read-only auto-properties
Read-only auto-properties provide a more concise syntax to create immutable types. You declare the auto-property
with only a get accessor:
The FirstName and LastName properties can be set only in the body of the constructor of the same class:
This feature enables true language support for creating immutable types and uses the more concise and
convenient auto-property syntax.
If adding this syntax doesn't remove an accessible method, it's a binary compatible change.
Auto-property initializers
Auto-property initializers let you declare the initial value for an auto-property as part of the property declaration.
public ICollection<double> Grades { get; } = new List<double>();
The Grades member is initialized where it's declared. That makes it easier to perform the initialization exactly once.
The initialization is part of the property declaration, making it easier to equate the storage allocation with the
public interface for Student objects.
using static
The using static enhancement enables you to import the static methods of a single class. You specify the class
you're using:
The Math does not contain any instance methods. You can also use using static to import a class' static methods
for a class that has both static and instance methods. One of the most useful examples is String:
NOTE
You must use the fully qualified class name, System.String in a static using statement. You cannot use the string
keyword instead.
When imported from a static using statement, extension methods are only in scope when called using the
extension method invocation syntax. They aren't in scope when called as a static method. You'll often see this in
LINQ queries. You can import the LINQ pattern by importing Enumerable, or Queryable.
You typically call extension methods using extension method invocation expressions. Adding the class name in the
rare case where you call them using static method call syntax resolves ambiguity.
The static using directive also imports any nested types. You can reference any nested types without
qualification.
Null-conditional operators
The null conditional operator makes null checks much easier and fluid. Replace the member access . with ?. :
In the preceding example, the variable first is assigned null if the person object is null . Otherwise, it is
assigned the value of the FirstName property. Most importantly, the ?. means that this line of code doesn't
generate a NullReferenceException if the person variable is null . Instead, it short-circuits and returns null . You
can also use a null conditional operator for array or indexer access. Replace [] with ?[] in the index expression.
The following expression returns a string , regardless of the value of person . You often use this construct with the
null coalescing operator to assign default values when one of the properties is null . When the expression short-
circuits, the null value returned is typed to match the full expression.
You can also use ?. to conditionally invoke methods. The most common use of member functions with the null
conditional operator is to safely invoke delegates (or event handlers) that may be null . You'll call the delegate's
Invoke method using the ?. operator to access the member. You can see an example in the delegate patterns
article.
The rules of the ?. operator ensure that the left-hand side of the operator is evaluated only once. It enables many
idioms, including the following example using event handlers:
// preferred in C# 6:
this.SomethingHappened?.Invoke(this, eventArgs);
Ensuring that the left side is evaluated only once also enables you to use any expression, including method calls, on
the left side of the ?.
String interpolation
With C# 6, the new string interpolation feature enables you to embed expressions in a string. Simply preface the
string with $ and use expressions between { and } instead of ordinals:
This example uses properties for the substituted expressions. You can use any expression. For example, you could
compute a student's grade point average as part of the interpolation:
The preceding line of code formats the value for Grades.Average() as a floating-point number with two decimal
places.
Often, you may need to format the string produced using a specific culture. You use the fact that the object
produced by a string interpolation can be implicitly converted to System.FormattableString. The FormattableString
instance contains the composite format string and the results of evaluating the expressions before converting them
to strings. Use the FormattableString.ToString(IFormatProvider) method to specify the culture when formatting a
string. The following example produces a string using the German (de-DE) culture. (By default, the German culture
uses the ',' character for the decimal separator, and the '.' character as the thousands separator.)
To get started with string interpolation, see the String interpolation in C# interactive tutorial, the String
interpolation article, and the String interpolation in C# tutorial.
Exception filters
Exception Filters are clauses that determine when a given catch clause should be applied. If the expression used for
an exception filter evaluates to true , the catch clause performs its normal processing on an exception. If the
expression evaluates to false , then the catch clause is skipped. One use is to examine information about an
exception to determine if a catch clause can process the exception:
if (IsNullOrWhiteSpace(lastName))
throw new ArgumentException(message: "Cannot be blank", paramName: nameof(lastName));
Another use is with XAML-based applications that implement the INotifyPropertyChanged interface:
public string LastName
{
get { return lastName; }
set
{
if (value != lastName)
{
lastName = value;
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(LastName)));
}
}
}
private string lastName;
The implementation details for adding await support inside catch and finally clauses ensure that the behavior
is consistent with the behavior for synchronous code. When code executed in a catch or finally clause throws,
execution looks for a suitable catch clause in the next surrounding block. If there was a current exception, that
exception is lost. The same happens with awaited expressions in catch and finally clauses: a suitable catch is
searched for, and the current exception, if any, is lost.
NOTE
This behavior is the reason it's recommended to write catch and finally clauses carefully, to avoid introducing new
exceptions.
You can use them with Dictionary<TKey,TValue> collections and other types where the accessible Add method
accepts more than one argument. The new syntax supports assignment using an index into the collection:
This feature means that associative containers can be initialized using syntax similar to what's been in place for
sequence containers for several versions.
In earlier versions of C#, calling that method using the method group syntax would fail:
Task.Run(DoThings);
The earlier compiler couldn't distinguish correctly between Task.Run(Action) and Task.Run(Func<Task>()) . In
previous versions, you'd need to use a lambda expression as an argument:
The Roslyn team maintains a list of breaking changes in the C# and Visual Basic compilers. You can find information
on those changes at these links on their GitHub repository:
Breaking changes in VS2019 version 16.8 which will be introduced for .NET 5.0 and C# 9.0
Breaking changes in VS2019 Update 1 and beyond compared to VS2019
Breaking changes since VS2017 (C# 7)
Breaking changes in Roslyn 3.0 (VS2019) from Roslyn 2.* (VS2017)
Breaking changes in Roslyn 2.0 (VS2017) from Roslyn 1.* (VS2015) and native C# compiler (VS2013 and
previous).
Breaking changes in Roslyn 1.0 (VS2015) from the native C# compiler (VS2013 and previous).
Unicode version change in C# 6
The history of C#
9/3/2020 • 11 minutes to read • Edit Online
This article provides a history of each major release of the C# language. The C# team is continuing to innovate and
add new features. Detailed language feature status, including features considered for upcoming releases can be
found on the dotnet/roslyn repository on GitHub.
IMPORTANT
The C# language relies on types and methods in what the C# specification defines as a standard library for some of the
features. The .NET platform delivers those types and methods in a number of packages. One example is exception processing.
Every throw statement or expression is checked to ensure the object being thrown is derived from Exception. Similarly,
every catch is checked to ensure that the type being caught is derived from Exception. Each version may add new
requirements. To use the latest language features in older environments, you may need to install specific libraries. These
dependencies are documented in the page for each specific version. You can learn more about the relationships between
language and library for background on this dependency.
The C# build tools consider the latest major language release the default language version. There may be point
releases between major releases, detailed in other articles in this section. To use the latest features in a point
release, you need to configure the compiler language version and select the version. There have been three-point
releases since C# 7.0:
C# 7.3:
C# 7.3 is available starting with Visual Studio 2017 version 15.7 and .NET Core 2.1 SDK.
C# 7.2:
C# 7.2 is available starting with Visual Studio 2017 version 15.5 and .NET Core 2.0 SDK.
C# 7.1:
C# 7.1 is available starting with Visual Studio 2017 version 15.3 and .NET Core 2.0 SDK.
C# version 1.0
When you go back and look, C# version 1.0, released with Visual Studio .NET 2002, looked a lot like Java. As part of
its stated design goals for ECMA, it sought to be a "simple, modern, general-purpose object-oriented language." At
the time, looking like Java meant it achieved those early design goals.
But if you look back on C# 1.0 now, you'd find yourself a little dizzy. It lacked the built-in async capabilities and
some of the slick functionality around generics you take for granted. As a matter of fact, it lacked generics
altogether. And LINQ? Not available yet. Those additions would take some years to come out.
C# version 1.0 looked stripped of features, compared to today. You'd find yourself writing some verbose code. But
yet, you have to start somewhere. C# version 1.0 was a viable alternative to Java on the Windows platform.
The major features of C# 1.0 included:
Classes
Structs
Interfaces
Events
Properties
Delegates
Operators and expressions
Statements
Attributes
C# version 1.2
C# version 1.2 shipped with Visual Studio .NET 2003. It contained a few small enhancements to the language. Most
notable is that starting with this version, the code generated in a foreach loop called Dispose on an IEnumerator
when that IEnumerator implemented IDisposable.
C# version 2.0
Now things start to get interesting. Let's take a look at some major features of C# 2.0, released in 2005, along with
Visual Studio 2005:
Generics
Partial types
Anonymous methods
Nullable value types
Iterators
Covariance and contravariance
Other C# 2.0 features added capabilities to existing features:
Getter/setter separate accessibility
Method group conversions (delegates)
Static classes
Delegate inference
While C# may have started as a generic Object-Oriented (OO) language, C# version 2.0 changed that in a hurry.
Once they had their feet under them, they went after some serious developer pain points. And they went after them
in a significant way.
With generics, types and methods can operate on an arbitrary type while still retaining type safety. For instance,
having a List<T> lets you have List<string> or List<int> and perform type-safe operations on those strings or
integers while you iterate through them. Using generics is better than create ListInt that derives from ArrayList
or casting from Object for every operation.
C# version 2.0 brought iterators. To put it succinctly, iterators let you examine all the items in a List (or other
Enumerable types) with a foreach loop. Having iterators as a first-class part of the language dramatically
enhanced readability of the language and people's ability to reason about the code.
And yet, C# continued to play a bit of catch-up with Java. Java had already released versions that included generics
and iterators. But that would soon change as the languages continued to evolve apart.
C# version 3.0
C# version 3.0 came in late 2007, along with Visual Studio 2008, though the full boat of language features would
actually come with .NET Framework version 3.5. This version marked a major change in the growth of C#. It
established C# as a truly formidable programming language. Let's take a look at some major features in this
version:
Auto-implemented properties
Anonymous types
Query expressions
Lambda expressions
Expression trees
Extension methods
Implicitly typed local variables
Partial methods
Object and collection initializers
In retrospect, many of these features seem both inevitable and inseparable. They all fit together strategically. It's
generally thought that C# version's killer feature was the query expression, also known as Language-Integrated
Query (LINQ).
A more nuanced view examines expression trees, lambda expressions, and anonymous types as the foundation
upon which LINQ is constructed. But, in either case, C# 3.0 presented a revolutionary concept. C# 3.0 had begun to
lay the groundwork for turning C# into a hybrid Object-Oriented / Functional language.
Specifically, you could now write SQL-style, declarative queries to perform operations on collections, among other
things. Instead of writing a for loop to compute the average of a list of integers, you could now do that as simply
as list.Average() . The combination of query expressions and extension methods made it look as though that list
of integers had gotten a whole lot smarter.
It took time for people to really grasp and integrate the concept, but they gradually did. And now, years later, code is
much more concise, simple, and functional.
C# version 4.0
C# version 4.0, released with Visual Studio 2010, would have had a difficult time living up to the groundbreaking
status of version 3.0. With version 3.0, C# had moved the language firmly out from the shadow of Java and into
prominence. The language was quickly becoming elegant.
The next version did introduce some interesting new features:
Dynamic binding
Named/optional arguments
Generic covariant and contravariant
Embedded interop types
Embedded interop types alleviated a deployment pain. Generic covariance and contravariance give you more
power to use generics, but they're a bit academic and probably most appreciated by framework and library authors.
Named and optional parameters let you eliminate many method overloads and provide convenience. But none of
those features are exactly paradigm altering.
The major feature was the introduction of the dynamic keyword. The dynamic keyword introduced into C# version
4.0 the ability to override the compiler on compile-time typing. By using the dynamic keyword, you can create
constructs similar to dynamically typed languages like JavaScript. You can create a dynamic x = "a string" and
then add six to it, leaving it up to the runtime to sort out what should happen next.
Dynamic binding gives you the potential for errors but also great power within the language.
C# version 5.0
C# version 5.0, released with Visual Studio 2012, was a focused version of the language. Nearly all of the effort for
that version went into another groundbreaking language concept: the async and await model for asynchronous
programming. Here is the major features list:
Asynchronous members
Caller info attributes
See Also
Code Project: Caller Info Attributes in C# 5.0
The caller info attribute lets you easily retrieve information about the context in which you're running without
resorting to a ton of boilerplate reflection code. It has many uses in diagnostics and logging tasks.
But async and await are the real stars of this release. When these features came out in 2012, C# changed the
game again by baking asynchrony into the language as a first-class participant. If you've ever dealt with long
running operations and the implementation of webs of callbacks, you probably loved this language feature.
C# version 6.0
With versions 3.0 and 5.0, C# had added major new features in an object-oriented language. With version 6.0,
released with Visual Studio 2015, it would go away from doing a dominant killer feature and instead release many
smaller features that made C# programming more productive. Here are some of them:
Static imports
Exception filters
Auto-property initializers
Expression bodied members
Null propagator
String interpolation
nameof operator
Index initializers
Other new features include:
Await in catch/finally blocks
Default values for getter-only properties
Each of these features is interesting in its own right. But if you look at them altogether, you see an interesting
pattern. In this version, C# eliminated language boilerplate to make code more terse and readable. So for fans of
clean, simple code, this language version was a huge win.
They did one other thing along with this version, though it's not a traditional language feature in itself. They
released Roslyn the compiler as a service. The C# compiler is now written in C#, and you can use the compiler as
part of your programming efforts.
C# version 7.0
C# version 7.0 was released with Visual Studio 2017. This version has some evolutionary and cool stuff in the vein
of C# 6.0, but without the compiler as a service. Here are some of the new features:
Out variables
Tuples and deconstruction
Pattern matching
Local functions
Expanded expression bodied members
Ref locals and returns
Other features included:
Discards
Binary Literals and Digit Separators
Throw expressions
All of these features offer cool new capabilities for developers and the opportunity to write even cleaner code than
ever. A highlight is condensing the declaration of variables to use with the out keyword and by allowing multiple
return values via tuple.
But C# is being put to ever broader use. .NET Core now targets any operating system and has its eyes firmly on the
cloud and on portability. These new capabilities certainly occupy the language designers' thoughts and time, in
addition to coming up with new features.
C# version 7.1
C# started releasing point releases with C# 7.1. This version added the language version selection configuration
element, three new language features, and new compiler behavior.
The new language features in this release are:
async Main method
The entry point for an application can have the async modifier.
default literal expressions
You can use default literal expressions in default value expressions when the target type can be inferred.
Inferred tuple element names
The names of tuple elements can be inferred from tuple initialization in many cases.
Pattern matching on generic type parameters
You can use pattern match expressions on variables whose type is a generic type parameter.
Finally, the compiler has two options -refout and -refonly that control reference assembly generation.
C# version 7.2
C# 7.2 added several small language features:
Techniques for writing safe efficient code
A combination of syntax improvements that enable working with value types using reference semantics.
Non-trailing named arguments
Named arguments can be followed by positional arguments.
Leading underscores in numeric literals
Numeric literals can now have leading underscores before any printed digits.
private protected access modifier
The private protected access modifier enables access for derived classes in the same assembly.
Conditional ref expressions
The result of a conditional expression ( ?: ) can now be a reference.
C# version 7.3
There are two main themes to the C# 7.3 release. One theme provides features that enable safe code to be as
performant as unsafe code. The second theme provides incremental improvements to existing features. In addition,
new compiler options were added in this release.
The following new features support the theme of better performance for safe code:
You can access fixed fields without pinning.
You can reassign ref local variables.
You can use initializers on stackalloc arrays.
You can use fixed statements with any type that supports a pattern.
You can use additional generic constraints.
The following enhancements were made to existing features:
You can test == and != with tuple types.
You can use expression variables in more locations.
You may attach attributes to the backing field of auto-implemented properties.
Method resolution when arguments differ by in has been improved.
Overload resolution now has fewer ambiguous cases.
The new compiler options are:
-publicsign to enable Open Source Software (OSS) signing of assemblies.
-pathmap to provide a mapping for source directories.
C# version 8.0
C# 8.0 is the first major C# release that specifically targets .NET Core. Some features rely on new CLR capabilities,
others on library types added only in .NET Core. C# 8.0 adds the following features and enhancements to the C#
language:
Readonly members
Default interface methods
Pattern matching enhancements:
Switch expressions
Property patterns
Tuple patterns
Positional patterns
Using declarations
Static local functions
Disposable ref structs
Nullable reference types
Asynchronous streams
Indices and ranges
Null-coalescing assignment
Unmanaged constructed types
Stackalloc in nested expressions
Enhancement of interpolated verbatim strings
Default interface members require enhancements in the CLR. Those features were added in the CLR for .NET Core
3.0. Ranges and indexes, and asynchronous streams require new types in the .NET Core 3.0 libraries. Nullable
reference types, while implemented in the compiler, is much more useful when libraries are annotated to provide
semantic information regarding the null state of arguments and return values. Those annotations are being added
in the .NET Core libraries.
Article originally published on the NDepend blog, courtesy of Erik Dietrich and Patrick Smacchia.
Relationships between language features and library
types
9/3/2020 • 2 minutes to read • Edit Online
The C# language definition requires a standard library to have certain types and certain accessible members on
those types. The compiler generates code that uses these required types and members for many different language
features. When necessary, there are NuGet packages that contain types needed for newer versions of the language
when writing code for environments where those types or members have not been deployed yet.
This dependency on standard library functionality has been part of the C# language since its first version. In that
version, examples included:
Exception - used for all compiler generated exceptions.
String - the C# string type is a synonym for String.
Int32 - synonym of int .
That first version was simple: the compiler and the standard library shipped together, and there was only one
version of each.
Subsequent versions of C# have occasionally added new types or members to the dependencies. Examples include:
INotifyCompletion, CallerFilePathAttribute and CallerMemberNameAttribute. C# 7.0 continues this by adding a
dependency on ValueTuple to implement the tuples language feature.
The language design team works to minimize the surface area of the types and members required in a compliant
standard library. That goal is balanced against a clean design where new library features are incorporated
seamlessly into the language. There will be new features in future versions of C# that require new types and
members in a standard library. It's important to understand how to manage those dependencies in your work.
Compatibility is a very important goal as new features are added to the C# language. In almost all cases, existing
code can be recompiled with a new compiler version without any issue.
More care may be required when you adopt new language features in a library. You may be creating a new library
with features found in the latest version and need to ensure apps built using previous versions of the compiler can
use it. Or you may be upgrading an existing library and many of your users may not have upgraded versions yet.
As you make decisions on adopting new features, you'll need to consider two variations of compatibility: source
compatible and binary compatible.
Incompatible changes
If a change is neither source compatible nor binar y compatible , source code changes along with recompilation
are required in dependent libraries and applications.
New code:
Source compatible changes introduce syntax that changes the compiled code for a public member, but in a way
that is compatible with existing call sites. For example, changing a method signature from a by value parameter to
an in by reference parameter is source compatible, but not binary compatible:
Original code:
New code:
The What's new articles note if introducing a feature that affects public declarations is source compatible or binary
compatible.
Types (C# Programming Guide)
9/3/2020 • 11 minutes to read • Edit Online
int a = 5;
int b = a + 2; //OK
// Error. Operator '+' cannot be applied to operands of type 'int' and 'bool'.
int c = a + test;
NOTE
C and C++ developers, notice that in C#, bool is not convertible to int.
The compiler embeds the type information into the executable file as metadata. The common language runtime
(CLR) uses that metadata at run time to further guarantee type safety when it allocates and reclaims memory.
Specifying types in variable declarations
When you declare a variable or constant in a program, you must either specify its type or use the var keyword to let
the compiler infer the type. The following example shows some variable declarations that use both built-in numeric
types and complex user-defined types:
// Declaration only:
float temperature;
string name;
MyClass myClass;
The types of method parameters and return values are specified in the method declaration. The following signature
shows a method that requires an int as an input argument and returns a string:
After a variable is declared, it cannot be re-declared with a new type, and it cannot be assigned a value that is not
compatible with its declared type. For example, you cannot declare an int and then assign it a Boolean value of
true . However, values can be converted to other types, for example when they are assigned to new variables or
passed as method arguments. A type conversion that does not cause data loss is performed automatically by the
compiler. A conversion that might cause data loss requires a cast in the source code.
For more information, see Casting and Type Conversions.
Built-in types
C# provides a standard set of built-in numeric types to represent integers, floating point values, Boolean
expressions, text characters, decimal values, and other types of data. There are also built-in string and object
types. These are available for you to use in any C# program. For the complete list of the built-in types, see Built-in
types.
Custom types
You use the struct, class, interface, and enum constructs to create your own custom types. The .NET class library
itself is a collection of custom types provided by Microsoft that you can use in your own applications. By default, the
most frequently used types in the class library are available in any C# program. Others become available only when
you explicitly add a project reference to the assembly in which they are defined. After the compiler has a reference
to the assembly, you can declare variables (and constants) of the types declared in that assembly in source code. For
more information, see .NET Class Library.
NOTE
You can see that the most commonly used types are all organized in the System namespace. However, the namespace in
which a type is contained has no relation to whether it is a value type or reference type.
Value types
Value types derive from System.ValueType, which derives from System.Object. Types that derive from
System.ValueType have special behavior in the CLR. Value type variables directly contain their values, which means
that the memory is allocated inline in whatever context the variable is declared. There is no separate heap allocation
or garbage collection overhead for value-type variables.
There are two categories of value types: struct and enum.
The built-in numeric types are structs, and they have fields and methods that you can access:
But you declare and assign values to them as if they were simple non-aggregate types:
byte num = 0xA;
int i = 5;
char c = 'Z';
Value types are sealed, which means, for example, that you cannot derive a type from System.Int32, and you cannot
define a struct to inherit from any user-defined class or struct because a struct can only inherit from
System.ValueType. However, a struct can implement one or more interfaces. You can cast a struct type to any
interface type that it implements; this causes a boxing operation to wrap the struct inside a reference type object on
the managed heap. Boxing operations occur when you pass a value type to a method that takes a System.Object or
any interface type as an input parameter. For more information, see Boxing and Unboxing.
You use the struct keyword to create your own custom value types. Typically, a struct is used as a container for a
small set of related variables, as shown in the following example:
For more information about structs, see Structure types. For more information about value types, see Value types.
The other category of value types is enum. An enum defines a set of named integral constants. For example, the
System.IO.FileMode enumeration in the .NET class library contains a set of named constant integers that specify
how a file should be opened. It is defined as shown in the following example:
The System.IO.FileMode.Create constant has a value of 2. However, the name is much more meaningful for humans
reading the source code, and for that reason it is better to use enumerations instead of constant literal numbers. For
more information, see System.IO.FileMode.
All enums inherit from System.Enum, which inherits from System.ValueType. All the rules that apply to structs also
apply to enums. For more information about enums, see Enumeration types.
Reference types
A type that is defined as a class, delegate, array, or interface is a reference type. At run time, when you declare a
variable of a reference type, the variable contains the value null until you explicitly create an object by using the new
operator, or assign it an object that has been created elsewhere by using new , as shown in the following example:
When the object is created, the memory is allocated on the managed heap, and the variable holds only a reference
to the location of the object. Types on the managed heap require overhead both when they are allocated and when
they are reclaimed by the automatic memory management functionality of the CLR, which is known as garbage
collection. However, garbage collection is also highly optimized, and in most scenarios it does not create a
performance issue. For more information about garbage collection, see Automatic Memory Management.
All arrays are reference types, even if their elements are value types. Arrays implicitly derive from the System.Array
class, but you declare and use them with the simplified syntax that is provided by C#, as shown in the following
example:
Reference types fully support inheritance. When you create a class, you can inherit from any other interface or class
that is not defined as sealed, and other classes can inherit from your class and override your virtual methods. For
more information about how to create your own classes, see Classes and Structs. For more information about
inheritance and virtual methods, see Inheritance.
Generic types
A type can be declared with one or more type parameters that serve as a placeholder for the actual type (the
concrete type) that client code will provide when it creates an instance of the type. Such types are called generic
types. For example, the .NET type System.Collections.Generic.List<T> has one type parameter that by convention is
given the name T. When you create an instance of the type, you specify the type of the objects that the list will
contain, for example, string:
List<string> stringList = new List<string>();
stringList.Add("String example");
// compile time error adding a type other than a string:
stringList.Add(4);
The use of the type parameter makes it possible to reuse the same class to hold any type of element, without having
to convert each element to object. Generic collection classes are called strongly typed collections because the
compiler knows the specific type of the collection's elements and can raise an error at compile-time if, for example,
you try to add an integer to the stringList object in the previous example. For more information, see Generics.
Related sections
For more information, see the following topics:
Casting and Type Conversions
Boxing and Unboxing
Using Type dynamic
Value Types
Reference Types
Classes and Structs
Anonymous Types
Generics
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for C#
syntax and usage.
See also
C# Reference
C# Programming Guide
Conversion of XML Data Types
Integral types
Nullable reference types
9/3/2020 • 7 minutes to read • Edit Online
C# 8.0 introduces nullable reference types and non-nullable reference types that enable you to make
important statements about the properties for reference type variables:
A reference isn't supposed to be null . When variables aren't supposed to be null, the compiler enforces
rules that ensure it's safe to dereference these variables without first checking that it isn't null:
The variable must be initialized to a non-null value.
The variable can never be assigned the value null .
A reference may be null . When variables may be null, the compiler enforces different rules to ensure that
you've correctly checked for a null reference:
The variable may only be dereferenced when the compiler can guarantee that the value isn't null.
These variables may be initialized with the default null value and may be assigned the value null in
other code.
This new feature provides significant benefits over the handling of reference variables in earlier versions of C#
where the design intent can't be determined from the variable declaration. The compiler didn't provide safety
against null reference exceptions for reference types:
A reference can be null . The compiler doesn't issue warnings when a reference type is initialized to null, or
later assigned to null. The compiler issues warnings when these variables are dereferenced without null checks.
A reference is assumed to be not null . The compiler doesn't issue any warnings when reference types are
dereferenced. The compiler issues warnings if a variable is set to an expression that may be null.
These warnings are emitted at compile time. The compiler doesn't add any null checks or other runtime constructs
in a nullable context. At runtime, a nullable reference and a non-nullable reference are equivalent.
With the addition of nullable reference types, you can declare your intent more clearly. The null value is the
correct way to represent that a variable doesn't refer to a value. Don't use this feature to remove all null values
from your code. Rather, you should declare your intent to the compiler and other developers that read your code.
By declaring your intent, the compiler informs you when you write code that is inconsistent with that intent.
A nullable reference type is noted using the same syntax as nullable value types: a ? is appended to the type
of the variable. For example, the following variable declaration represents a nullable string variable, name :
string? name;
Any variable where the ? isn't appended to the type name is a non-nullable reference type . That includes all
reference type variables in existing code when you've enabled this feature.
The compiler uses static analysis to determine if a nullable reference is known to be non-null. The compiler warns
you if you dereference a nullable reference when it may be null. You can override this behavior by using the null-
forgiving operator ! following a variable name. For example, if you know the name variable isn't null but the
compiler issues a warning, you can write the following code to override the compiler's analysis:
name!.Length;
Nullability of types
Any reference type can have one of four nullabilities, which describes when warnings are generated:
Nonnullable: Null can't be assigned to variables of this type. Variables of this type don't need to be null-checked
before dereferencing.
Nullable: Null can be assigned to variables of this type. Dereferencing variables of this type without first
checking for null causes a warning.
Oblivious: Oblivious is the pre-C# 8.0 state. Variables of this type can be dereferenced or assigned without
warnings.
Unknown: Unknown is generally for type parameters where constraints don't tell the compiler that the type
must be nullable or nonnullable.
The nullability of a type in a variable declaration is controlled by the nullable context in which the variable is
declared.
Nullable contexts
Nullable contexts enable fine-grained control for how the compiler interprets reference type variables. The
nullable annotation context of any given source line is either enabled or disabled. You can think of the pre-C#
8.0 compiler as compiling all your code in a disabled nullable context: any reference type may be null. The
nullable warnings context may also be enabled or disabled. The nullable warnings context specifies the
warnings generated by the compiler using its flow analysis.
The nullable annotation context and nullable warning context can be set for a project using the Nullable element
in your .csproj file. This element configures how the compiler interprets the nullability of types and what warnings
are generated. Valid settings are:
enable : The nullable annotation context is enabled . The nullable warning context is enabled .
Variables of a reference type, string for example, are non-nullable. All nullability warnings are enabled.
warnings : The nullable annotation context is disabled . The nullable warning context is enabled .
Variables of a reference type are oblivious. All nullability warnings are enabled.
annotations : The nullable annotation context is enabled . The nullable warning context is disabled .
Variables of a reference type, string for example, are non-nullable. All nullability warnings are disabled.
disable : The nullable annotation context is disabled . The nullable warning context is disabled .
Variables of a reference type are oblivious, just like earlier versions of C#. All nullability warnings are
disabled.
Example :
<Nullable>enable</Nullable>
You can also use directives to set these same contexts anywhere in your project:
#nullable enable : Sets the nullable annotation context and nullable warning context to enabled .
#nullable disable : Sets the nullable annotation context and nullable warning context to disabled .
#nullable restore : Restores the nullable annotation context and nullable warning context to the project
settings.
#nullable disable warnings : Set the nullable warning context to disabled .
#nullable enable warnings : Set the nullable warning context to enabled .
#nullable restore warnings : Restores the nullable warning context to the project settings.
#nullable disable annotations : Set the nullable annotation context to disabled .
#nullable enable annotations : Set the nullable annotation context to enabled .
#nullable restore annotations : Restores the annotation warning context to the project settings.
By default, nullable annotation and warning contexts are disabled , including new projects. That means that your
existing code compiles without changes and without generating any new warnings.
These options provide two distinct strategies to update an existing codebase to use nullable reference types.
See also
Draft nullable reference types specification
Intro to nullable references tutorial
Migrate an existing codebase to nullable references
-nullable (C# Compiler option)
Update libraries to use nullable reference types and
communicate nullable rules to callers
5/9/2020 • 10 minutes to read • Edit Online
The addition of nullable reference types means you can declare whether or not a null value is allowed or
expected for every variable. In addition, you can apply a number of attributes: AllowNull , DisallowNull ,
MaybeNull , NotNull , NotNullWhen , MaybeNullWhen , and NotNullIfNotNull to completely describe the null states of
argument and return values. That provides a great experience as you write code. You get warnings if a non-nullable
variable might be set to null . You get warnings if a nullable variable isn't null-checked before you dereference it.
Updating your libraries can take time, but the payoffs are worth it. The more information you provide to the
compiler about when a null value is allowed or prohibited, the better warnings users of your API will get. Let's
start with a familiar example. Imagine your library has the following API to retrieve a resource string:
The preceding example follows the familiar Try* pattern in .NET. There are two reference arguments for this API:
the key and the message parameter. This API has the following rules relating to the nullness of these arguments:
Callers shouldn't pass null as the argument for key .
Callers can pass a variable whose value is null as the argument for message .
If the TryGetMessage method returns true , the value of message isn't null. If the return value is false, the
value of message (and its null state) is null.
The rule for key can be completely expressed by the variable type: key should be a non-nullable reference type.
The message parameter is more complex. It allows null as the argument, but guarantees that, on success, that
out argument isn't null. For these scenarios, you need a richer vocabulary to describe the expectations.
Updating your library for nullable references requires more than sprinkling ? on some of the variables and type
names. The preceding example shows that you need to examine your APIs and consider your expectations for each
input argument. Consider the guarantees for the return value, and any out or ref arguments upon the method's
return. Then communicate those rules to the compiler, and the compiler will provide warnings when callers don't
abide by those rules.
This work takes time. Let's start with strategies to make your library or application nullable-aware, while balancing
other requirements and deliverables. You'll see how to balance ongoing development enabling nullable reference
types. You'll learn challenges for generic type definitions. You'll learn to apply attributes to describe pre- and post-
conditions on individual APIs.
The return value indicates success or failure, and carries the value if the value was found. In many cases, changing
API signatures can improve how they communicate null values.
However, for public libraries, or libraries with large user bases, you may prefer not introducing any API signature
changes. For those cases, and other common patterns, you can apply attributes to more clearly define when an
argument or return value may be null . Whether or not you consider changing the surface of your API, you'll likely
find that type annotations alone aren't sufficient for describing null values for arguments or return values. In
those instances, you can apply attributes to more clearly describe an API.
class Student
{
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
class Student
{
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
For this DTO, the only property that may be null is VehicleRegistration .
However, the compiler raises CS8618 warnings for both FirstName and LastName , indicating the non-nullable
properties are uninitialized.
There are three options available to you that resolve the compiler warnings in a way that maintains the original
intent. Any of these options are valid; you should choose the one that best suits your coding style and design
requirements.
Initialize in the constructor
The ideal way to resolve the uninitialized warnings is to initialize the properties in the constructor:
class Student
{
public Student(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
This approach only works if the library that you use to instantiate the class supports passing parameters in the
constructor.
In addition, a library may support passing some properties in the constructor, but not all. For example, EF Core
supports constructor binding for normal column properties, but not navigation properties.
Check the documentation on the library that instantiates your class, to understand the extent to which it supports
constructor binding.
Property with nullable backing field
If constructor binding won't work for you, one way to deal with this problem is to have a non-nullable property
with a nullable backing field:
private string? _firstName;
[Required]
public string FirstName
{
set => _firstName = value;
get => _firstName
?? throw new InvalidOperationException("Uninitialized " + nameof(FirstName))
}
In this scenario, if the property is accessed before it has been initialized, then the code throws an
FirstName
InvalidOperationException , because the API contract has been used incorrectly.
You should consider that some libraries may have special considerations when using backing fields. For example,
EF Core may need to be configured to use backing fields correctly.
Initialize the property to null
As a terser alternative to using a nullable backing field, or if the library that instantiates your class is not compatible
with that approach, you can simply initialize the property to null directly, with the help of the null-forgiving
operator ( ! ):
[Required]
public string FirstName { get; set; } = null!;
[Required]
public string LastName { get; set; } = null!;
You will never observe an actual null value at runtime except as a result of a programming bug, by accessing the
property before it has been properly initialized.
See also
Migrate an existing codebase to nullable references
Working with Nullable Reference Types in EF Core
Namespaces (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
Namespaces are heavily used in C# programming in two ways. First, .NET uses namespaces to organize its many
classes, as follows:
System.Console.WriteLine("Hello World!");
System is a namespace and Console is a class in that namespace. The using keyword can be used so that the
complete name is not required, as in the following example:
using System;
Console.WriteLine("Hello");
Console.WriteLine("World!");
namespace SampleNamespace
{
class SampleClass
{
public void SampleMethod()
{
System.Console.WriteLine(
"SampleMethod inside SampleNamespace");
}
}
}
Namespaces overview
Namespaces have the following properties:
They organize large code projects.
They are delimited by using the . operator.
The using directive obviates the requirement to specify the name of the namespace for every class.
The global namespace is the "root" namespace: global::System will always refer to the .NET System
namespace.
C# language specification
For more information, see the Namespaces section of the C# language specification.
See also
C# Programming Guide
Using Namespaces
How to use the My namespace
Identifier names
using Directive
:: Operator
Types, variables, and values
9/3/2020 • 6 minutes to read • Edit Online
C# is a strongly typed language. Every variable and constant has a type, as does every expression that evaluates to
a value. Every method signature specifies a type for each input parameter and for the return value. The .NET
Framework class library defines a set of built-in numeric types as well as more complex types that represent a wide
variety of logical constructs, such as the file system, network connections, collections and arrays of objects, and
dates. A typical C# program uses types from the class library as well as user-defined types that model the concepts
that are specific to the program's problem domain.
The information stored in a type can include the following:
The storage space that a variable of the type requires.
The maximum and minimum values that it can represent.
The members (methods, fields, events, and so on) that it contains.
The base type it inherits from.
The location where the memory for variables will be allocated at run time.
The kinds of operations that are permitted.
The compiler uses type information to make sure that all operations that are performed in your code are type safe.
For example, if you declare a variable of type int, the compiler allows you to use the variable in addition and
subtraction operations. If you try to perform those same operations on a variable of type bool, the compiler
generates an error, as shown in the following example:
int a = 5;
int b = a + 2; //OK
// Error. Operator '+' cannot be applied to operands of type 'int' and 'bool'.
int c = a + test;
NOTE
C and C++ developers, notice that in C#, bool is not convertible to int.
The compiler embeds the type information into the executable file as metadata. The common language runtime
(CLR) uses that metadata at run time to further guarantee type safety when it allocates and reclaims memory.
The types of method parameters and return values are specified in the method signature. The following signature
shows a method that requires an int as an input argument and returns a string:
After a variable is declared, it cannot be re-declared with a new type, and it cannot be assigned a value that is not
compatible with its declared type. For example, you cannot declare an int and then assign it a Boolean value of
true . However, values can be converted to other types, for example when they are assigned to new variables or
passed as method arguments. A type conversion that does not cause data loss is performed automatically by the
compiler. A conversion that might cause data loss requires a cast in the source code.
For more information, see Casting and type conversions.
Built-in types
C# provides a standard set of built-in numeric types to represent integers, floating point values, Boolean
expressions, text characters, decimal values, and other types of data. There are also built-in string and object types.
These are available for you to use in any C# program. For the complete list of the built-in types, see Built-in types.
Custom types
You use the struct, class, interface, and enum constructs to create your own custom types. The .NET Framework
class library itself is a collection of custom types provided by Microsoft that you can use in your own applications.
By default, the most frequently used types in the class library are available in any C# program. Others become
available only when you explicitly add a project reference to the assembly in which they are defined. After the
compiler has a reference to the assembly, you can declare variables (and constants) of the types declared in that
assembly in source code.
Generic types
A type can be declared with one or more type parameters that serve as a placeholder for the actual type (the
concrete type) that client code will provide when it creates an instance of the type. Such types are called generic
types. For example, the .NET Framework type List<T> has one type parameter that by convention is given the name
T. When you create an instance of the type, you specify the type of the objects that the list will contain, for example,
string:
List<string> strings = new List<string>();
The use of the type parameter makes it possible to reuse the same class to hold any type of element, without
having to convert each element to object. Generic collection classes are called strongly typed collections because
the compiler knows the specific type of the collection's elements and can raise an error at compile-time if, for
example, you try to add an integer to the strings object in the previous example. For more information, see
Generics.
See also
Structure types
Enumeration types
Classes
Classes (C# Programming Guide)
4/23/2020 • 5 minutes to read • Edit Online
Reference types
A type that is defined as a class is a reference type. At run time, when you declare a variable of a reference type, the
variable contains the value null until you explicitly create an instance of the class by using the new operator, or
assign it an object of a compatible type that may have been created elsewhere, as shown in the following example:
//Declaring another object of the same type, assigning it the value of the first object.
MyClass mc2 = mc;
When the object is created, enough memory is allocated on the managed heap for that specific object, and the
variable holds only a reference to the location of said object. Types on the managed heap require overhead both
when they are allocated and when they are reclaimed by the automatic memory management functionality of the
CLR, which is known as garbage collection. However, garbage collection is also highly optimized and in most
scenarios, it does not create a performance issue. For more information about garbage collection, see Automatic
memory management and garbage collection.
Declaring Classes
Classes are declared by using the class keyword followed by a unique identifier, as shown in the following example:
The class keyword is preceded by the access level. Because public is used in this case, anyone can create instances
of this class. The name of the class follows the class keyword. The name of the class must be a valid C# identifier
name. The remainder of the definition is the class body, where the behavior and data are defined. Fields, properties,
methods, and events on a class are collectively referred to as class members.
Creating objects
Although they are sometimes used interchangeably, a class and an object are different things. A class defines a type
of object, but it is not an object itself. An object is a concrete entity based on a class, and is sometimes referred to as
an instance of a class.
Objects can be created by using the new keyword followed by the name of the class that the object will be based on,
like this:
When an instance of a class is created, a reference to the object is passed back to the programmer. In the previous
example, object1 is a reference to an object that is based on Customer . This reference refers to the new object but
does not contain the object data itself. In fact, you can create an object reference without creating an object at all:
Customer object2;
We don't recommend creating object references such as this one that don't refer to an object because trying to
access an object through such a reference will fail at run time. However, such a reference can be made to refer to an
object, either by creating a new object, or by assigning it to an existing object, such as this:
This code creates two object references that both refer to the same object. Therefore, any changes to the object
made through object3 are reflected in subsequent uses of object4 . Because objects that are based on classes are
referred to by reference, classes are known as reference types.
Class inheritance
Classes fully support inheritance, a fundamental characteristic of object-oriented programming. When you create a
class, you can inherit from any other interface or class that is not defined as sealed, and other classes can inherit
from your class and override class virtual methods.
Inheritance is accomplished by using a derivation, which means a class is declared by using a base class from which
it inherits data and behavior. A base class is specified by appending a colon and the name of the base class
following the derived class name, like this:
When a class declares a base class, it inherits all the members of the base class except the constructors. For more
information, see Inheritance.
Unlike C++, a class in C# can only directly inherit from one base class. However, because a base class may itself
inherit from another class, a class may indirectly inherit multiple base classes. Furthermore, a class can directly
implement more than one interface. For more information, see Interfaces.
A class can be declared abstract. An abstract class contains abstract methods that have a signature definition but no
implementation. Abstract classes cannot be instantiated. They can only be used through derived classes that
implement the abstract methods. By contrast, a sealed class does not allow other classes to derive from it. For more
information, see Abstract and Sealed Classes and Class Members.
Class definitions can be split between different source files. For more information, see Partial Classes and Methods.
Example
The following example defines a public class that contains an auto-implemented property, a method, and a special
method called a constructor. For more information, see Properties, Methods, and Constructors topics. The instances
of the class are then instantiated with the new keyword.
using System;
C# Language Specification
For more information, see the C# Language Specification. The language specification is the definitive source for C#
syntax and usage.
See also
C# Programming Guide
Object-Oriented Programming
Polymorphism
Identifier names
Members
Methods
Constructors
Finalizers
Objects
Deconstructing tuples and other types
9/3/2020 • 10 minutes to read • Edit Online
A tuple provides a lightweight way to retrieve multiple values from a method call. But once you retrieve the tuple,
you have to handle its individual elements. Doing this on an element-by-element basis is cumbersome, as the
following example shows. The QueryCityData method returns a 3-tuple, and each of its elements is assigned to a
variable in a separate operation.
using System;
Retrieving multiple field and property values from an object can be equally cumbersome: you have to assign a field
or property value to a variable on a member-by-member basis.
Starting with C# 7.0, you can retrieve multiple elements from a tuple or retrieve multiple field, property, and
computed values from an object in a single deconstruct operation. When you deconstruct a tuple, you assign its
elements to individual variables. When you deconstruct an object, you assign selected values to individual
variables.
Deconstructing a tuple
C# features built-in support for deconstructing tuples, which lets you unpackage all the items in a tuple in a single
operation. The general syntax for deconstructing a tuple is similar to the syntax for defining one: you enclose the
variables to which each element is to be assigned in parentheses in the left side of an assignment statement. For
example, the following statement assigns the elements of a 4-tuple to four separate variables:
You can use the var keyword so that C# infers the type of each variable. You place the var keyword
outside of the parentheses. The following example uses type inference when deconstructing the 3-tuple
returned by the QueryCityData method.
You can also use the var keyword individually with any or all of the variable declarations inside the
parentheses.
Note that you cannot specify a specific type outside the parentheses even if every field in the tuple has the same
type. This generates compiler error CS8136, "Deconstruction 'var (...)' form disallows a specific type for 'var'.".
Note that you must also assign each element of the tuple to a variable. If you omit any elements, the compiler
generates error CS8132, "Cannot deconstruct a tuple of 'x' elements into 'y' variables."
Note that you cannot mix declarations and assignments to existing variables on the left-hand side of a
deconstruction. The compiler generates error CS8184, "a deconstruction cannot mix declarations and expressions
on the left-hand-side." when the members include newly declared and existing variables.
using System;
using System.Collections.Generic;
private static (string, double, int, int, int, int) QueryCityDataForYears(string name, int year1, int
year2)
{
int population1 = 0, population2 = 0;
double area = 0;
public void Deconstruct(out string fname, out string mname, out string lname)
You can then deconstruct an instance of the Person class named p with an assignment like the following:
var (fName, mName, lName) = p;
The following example overloads the Deconstruct method to return various combinations of properties of a
Person object. Individual overloads return:
public void Deconstruct(out string fname, out string mname, out string lname)
{
fname = FirstName;
mname = MiddleName;
lname = LastName;
}
Because you can overload the Deconstruct method to reflect groups of data that are commonly extracted from an
object, you should be careful to define Deconstruct methods with signatures that are distinctive and
unambiguous. Multiple Deconstruct methods that have the same number of out parameters or the same
number and type of out parameters in a different order can cause confusion.
The overloaded Deconstruct method in the following example illustrates one possible source of confusion. The
first overload returns the first name, middle name, last name, and age of a Person object, in that order. The second
overload returns name information only along with annual income, but the first, middle, and last name are in a
different order. This makes it easy to confuse the order of arguments when deconstructing a Person instance.
using System;
public void Deconstruct(out string fname, out string mname, out string lname, out int age)
{
fname = FirstName;
mname = MiddleName;
lname = LastName;
public void Deconstruct(out string lname, out string fname, out string mname, out decimal income)
{
fname = FirstName;
mname = MiddleName;
lname = LastName;
income = AnnualIncome;
}
}
using System;
using System.Collections.Generic;
using System.Reflection;
if (getter != null)
{
if (getter.IsPublic)
getAccessTemp = "public";
else if (getter.IsPrivate)
getAccessTemp = "private";
else if (getter.IsAssembly)
getAccessTemp = "internal";
else if (getter.IsFamily)
getAccessTemp = "protected";
else if (getter.IsFamilyOrAssembly)
getAccessTemp = "protected internal";
}
if (setter != null)
{
if (setter.IsPublic)
setAccessTemp = "public";
setAccessTemp = "public";
else if (setter.IsPrivate)
setAccessTemp = "private";
else if (setter.IsAssembly)
setAccessTemp = "internal";
else if (setter.IsFamily)
setAccessTemp = "protected";
else if (setter.IsFamilyOrAssembly)
setAccessTemp = "protected internal";
}
if (!hasGetAndSet | sameAccess)
{
Console.WriteLine(accessibility);
}
else
{
Console.WriteLine($"\n The get accessor: {getAccessibility}");
Console.WriteLine($" The set accessor: {setAccessibility}");
}
}
}
// The example displays the following output:
// The System.DateTime.Now property:
// PropertyType: DateTime
// Static: True
// Read-only: True
// Indexed: False
//
// Accessibility of the System.Collections.Generic.List`1.Item property: public
See also
Discards
Tuple types
Interfaces (C# Programming Guide)
9/3/2020 • 4 minutes to read • Edit Online
An interface contains definitions for a group of related functionalities that a non-abstract class or a struct must
implement. An interface may define static methods, which must have an implementation. Beginning with C# 8.0,
an interface may define a default implementation for members. An interface may not declare instance data such as
fields, auto-implemented properties, or property-like events.
By using interfaces, you can, for example, include behavior from multiple sources in a class. That capability is
important in C# because the language doesn't support multiple inheritance of classes. In addition, you must use an
interface if you want to simulate inheritance for structs, because they can't actually inherit from another struct or
class.
You define an interface by using the interface keyword as the following example shows.
interface IEquatable<T>
{
bool Equals(T obj);
}
The name of an interface must be a valid C# identifier name. By convention, interface names begin with a capital I .
Any class or struct that implements the IEquatable<T> interface must contain a definition for an Equals method that
matches the signature that the interface specifies. As a result, you can count on a class that implements
IEquatable<T> to contain an Equals method with which an instance of the class can determine whether it's equal
to another instance of the same class.
The definition of IEquatable<T> doesn't provide an implementation for Equals . A class or struct can implement
multiple interfaces, but a class can only inherit from a single class.
For more information about abstract classes, see Abstract and Sealed Classes and Class Members.
Interfaces can contain instance methods, properties, events, indexers, or any combination of those four member
types. Interfaces may contain static constructors, fields, constants, or operators. For links to examples, see Related
Sections. An interface can't contain instance fields, instance constructors, or finalizers. Interface members are public
by default.
To implement an interface member, the corresponding member of the implementing class must be public, non-
static, and have the same name and signature as the interface member.
When a class or struct implements an interface, the class or struct must provide an implementation for all of the
members that the interface declares but doesn't provide a default implementation for. However, if a base class
implements an interface, any class that's derived from the base class inherits that implementation.
The following example shows an implementation of the IEquatable<T> interface. The implementing class, Car ,
must provide an implementation of the Equals method.
public class Car : IEquatable<Car>
{
public string Make {get; set;}
public string Model { get; set; }
public string Year { get; set; }
Properties and indexers of a class can define extra accessors for a property or indexer that's defined in an interface.
For example, an interface might declare a property that has a get accessor. The class that implements the interface
can declare the same property with both a get and set accessor. However, if the property or indexer uses explicit
implementation, the accessors must match. For more information about explicit implementation, see Explicit
Interface Implementation and Interface Properties.
Interfaces can inherit from one or more interfaces. The derived interface inherits the members from its base
interfaces. A class that implements a derived interface must implement all members in the derived interface,
including all members of the derived interface's base interfaces. That class may be implicitly converted to the
derived interface or any of its base interfaces. A class might include an interface multiple times through base classes
that it inherits or through interfaces that other interfaces inherit. However, the class can provide an implementation
of an interface only one time and only if the class declares the interface as part of the definition of the class (
class ClassName : InterfaceName ). If the interface is inherited because you inherited a base class that implements
the interface, the base class provides the implementation of the members of the interface. However, the derived
class can reimplement any virtual interface members instead of using the inherited implementation. When
interfaces declare a default implementation of a method, any class implementing that interface inherits that
implementation. Implementations defined in interfaces are virtual and the implementing class may override that
implementation.
A base class can also implement interface members by using virtual members. In that case, a derived class can
change the interface behavior by overriding the virtual members. For more information about virtual members, see
Polymorphism.
Interfaces summary
An interface has the following properties:
An interface is typically like an abstract base class with only abstract members. Any class or struct that
implements the interface must implement all its members. Optionally, an interface may define default
implementations for some or all of its members. For more information, see default interface methods.
An interface can't be instantiated directly. Its members are implemented by any class or struct that implements
the interface.
A class or struct can implement multiple interfaces. A class can inherit a base class and also implement one or
more interfaces.
Related Sections
Interface Properties
Indexers in Interfaces
How to implement interface events
Classes and Structs
Inheritance
Interfaces
Methods
Polymorphism
Abstract and Sealed Classes and Class Members
Properties
Events
Indexers
See also
C# Programming Guide
Inheritance
Identifier names
Methods in (C#)
9/3/2020 • 21 minutes to read • Edit Online
A method is a code block that contains a series of statements. A program causes the statements to be executed by
calling the method and specifying any required method arguments. In C#, every executed instruction is performed
in the context of a method. The Main method is the entry point for every C# application and it is called by the
common language runtime (CLR) when the program is started.
NOTE
This topic discusses named methods. For information about anonymous functions, see Anonymous Functions.
Method signatures
Methods are declared in a class or struct by specifying:
An optional access level, such as public or private . The default is private .
Optional modifiers such as abstract or sealed .
The return value, or void if the method has none.
The method name.
Any method parameters. Method parameters are enclosed in parentheses and are separated by commas. Empty
parentheses indicate that the method requires no parameters.
These parts together form the method signature.
IMPORTANT
A return type of a method is not part of the signature of the method for the purposes of method overloading. However, it is
part of the signature of the method when determining the compatibility between a delegate and the method that it points
to.
The following example defines a class named Motorcycle that contains five methods:
using System;
Method invocation
Methods can be either instance or static. Invoking an instance method requires that you instantiate an object and
call the method on that object; an instance method operates on that instance and its data. You invoke a static
method by referencing the name of the type to which the method belongs; static methods do not operate on
instance data. Attempting to call a static method through an object instance generates a compiler error.
Calling a method is like accessing a field. After the object name (if you are calling an instance method) or the type
name (if you are calling a static method), add a period, the name of the method, and parentheses. Arguments are
listed within the parentheses, and are separated by commas.
The method definition specifies the names and types of any parameters that are required. When a caller invokes
the method, it provides concrete values, called arguments, for each parameter. The arguments must be compatible
with the parameter type, but the argument name, if one is used in the calling code, does not have to be the same as
the parameter named defined in the method. In the following example, the Square method includes a single
parameter of type int named i. The first method call passes the Square method a variable of type int named
num; the second, a numeric constant; and the third, an expression.
The most common form of method invocation used positional arguments; it supplies arguments in the same order
as method parameters. The methods of the Motorcycle class can therefore be called as in the following example.
The call to the Drive method, for example, includes two arguments that correspond to the two parameters in the
method's syntax. The first becomes the value of the miles parameter, the second the value of the speed
parameter.
class TestMotorcycle : Motorcycle
{
public override double GetTopSpeed()
{
return 108.4;
}
moto.StartEngine();
moto.AddGas(15);
moto.Drive(5, 20);
double speed = moto.GetTopSpeed();
Console.WriteLine("My top speed is {0}", speed);
}
}
You can also used named arguments instead of positional arguments when invoking a method. When using named
arguments, you specify the parameter name followed by a colon (":") and the argument. Arguments to the method
can appear in any order, as long as all required arguments are present. The following example uses named
arguments to invoke the TestMotorcycle.Drive method. In this example, the named arguments are passed in the
opposite order from the method's parameter list.
using System;
You can invoke a method using both positional arguments and named arguments. However, a positional argument
cannot follow a named argument. The following example invokes the TestMotorcycle.Drive method from the
previous example using one positional argument and one named argument.
using System;
Types can override inherited members by using the override keyword and providing an implementation for the
overridden method. The method signature must be the same as that of the overridden method. The following
example is like the previous one, except that it overrides the Equals(Object) method. (It also overrides the
GetHashCode() method, since the two methods are intended to provide consistent results.)
using System;
Passing parameters
Types in C# are either value types or reference types. For a list of built-in value types, see Types. By default, both
value types and reference types are passed to a method by value.
Passing parameters by value
When a value type is passed to a method by value, a copy of the object instead of the object itself is passed to the
method. Therefore, changes to the object in the called method have no effect on the original object when control
returns to the caller.
The following example passes a value type to a method by value, and the called method attempts to change the
value type's value. It defines a variable of type int , which is a value type, initializes its value to 20, and passes it to
a method named ModifyValue that changes the variable's value to 30. When the method returns, however, the
variable's value remains unchanged.
using System;
When an object of a reference type is passed to a method by value, a reference to the object is passed by value.
That is, the method receives not the object itself, but an argument that indicates the location of the object. If you
change a member of the object by using this reference, the change is reflected in the object when control returns to
the calling method. However, replacing the object passed to the method has no effect on the original object when
control returns to the caller.
The following example defines a class (which is a reference type) named SampleRefType . It instantiates a
SampleRefType object, assigns 44 to its value field, and passes the object to the ModifyObject method. This
example does essentially the same thing as the previous example -- it passes an argument by value to a method.
But because a reference type is used, the result is different. The modification that is made in ModifyObject to the
obj.value field also changes the value field of the argument, rt , in the Main method to 33, as the output from
the example shows.
using System;
The following example is identical to the previous one, except the value is passed by reference to the ModifyValue
method. When the value of the parameter is modified in the ModifyValue method, the change in value is reflected
when control returns to the caller.
using System;
A common pattern that uses by ref parameters involves swapping the values of variables. You pass two variables to
a method by reference, and the method swaps their contents. The following example swaps integer values.
using System;
Passing a reference-type parameter allows you to change the value of the reference itself, rather than the value of
its individual elements or fields.
Parameter arrays
Sometimes, the requirement that you specify the exact number of arguments to your method is restrictive. By
using the params keyword to indicate that a parameter is a parameter array, you allow your method to be called
with a variable number of arguments. The parameter tagged with the params keyword must be an array type, and
it must be the last parameter in the method's parameter list.
A caller can then invoke the method in either of three ways:
By passing an array of the appropriate type that contains the desired number of elements.
By passing a comma-separated list of individual arguments of the appropriate type to the method.
By not providing an argument to the parameter array.
The following example defines a method named GetVowels that returns all the vowels from a parameter array. The
Main method illustrates all three ways of invoking the method. Callers are not required to supply any arguments
for parameters that include the params modifier. In that case, the parameter is null .
using System;
using System.Linq;
class Example
{
static void Main()
{
string fromArray = GetVowels(new[] { "apple", "banana", "pear" });
Console.WriteLine($"Vowels from array: '{fromArray}'");
If a method includes both required and optional parameters, optional parameters are defined at the end of the
parameter list, after all required parameters.
The following example defines a method, ExampleMethod , that has one required and two optional parameters.
using System;
If a method with multiple optional arguments is invoked using positional arguments, the caller must supply an
argument for all optional parameters from the first one to the last one for which an argument is supplied. In the
case of the ExampleMethod method, for example, if the caller supplies an argument for the description parameter,
it must also supply one for the optionalInt parameter. opt.ExampleMethod(2, 2, "Addition of 2 and 2"); is a valid
method call; opt.ExampleMethod(2, , "Addition of 2 and 0"); generates an "Argument missing" compiler error.
If a method is called using named arguments or a combination of positional and named arguments, the caller can
omit any arguments that follow the last positional argument in the method call.
The following example calls the ExampleMethod method three times. The first two method calls use positional
arguments. The first omits both optional arguments, while the second omits the last argument. The third method
call supplies a positional argument for the required parameter, but uses a named argument to supply a value to the
description parameter while omitting the optionalInt argument.
The use of optional parameters affects overload resolution, or the way in which the C# compiler determines which
particular overload should be invoked by a method call, as follows:
A method, indexer, or constructor is a candidate for execution if each of its parameters either is optional or
corresponds, by name or by position, to a single argument in the calling statement, and that argument can be
converted to the type of the parameter.
If more than one candidate is found, overload resolution rules for preferred conversions are applied to the
arguments that are explicitly specified. Omitted arguments for optional parameters are ignored.
If two candidates are judged to be equally good, preference goes to a candidate that does not have optional
parameters for which arguments were omitted in the call. This is a consequence of a general preference in
overload resolution for candidates that have fewer parameters.
Return values
Methods can return a value to the caller. If the return type (the type listed before the method name) is not void ,
the method can return the value by using the return keyword. A statement with the return keyword followed by
a variable, constant, or expression that matches the return type will return that value to the method caller. Methods
with a non-void return type are required to use the return keyword to return a value. The return keyword also
stops the execution of the method.
If the return type is void , a return statement without a value is still useful to stop the execution of the method.
Without the return keyword, the method will stop executing when it reaches the end of the code block.
For example, these two methods use the return keyword to return integers:
class SimpleMath
{
public int AddTwoNumbers(int number1, int number2)
{
return number1 + number2;
}
To use a value returned from a method, the calling method can use the method call itself anywhere a value of the
same type would be sufficient. You can also assign the return value to a variable. For example, the following two
code examples accomplish the same goal:
Using a local variable, in this case, result , to store a value is optional. It may help the readability of the code, or it
may be necessary if you need to store the original value of the argument for the entire scope of the method.
Sometimes, you want your method to return more than a single value. Starting with C# 7.0, you can do this easily
by using tuple types and tuple literals. The tuple type defines the data types of the tuple's elements. Tuple literals
provide the actual values of the returned tuple. In the following example, (string, string, string, int) defines
the tuple type that is returned by the GetPersonalInfo method. The expression
(per.FirstName, per.MiddleName, per.LastName, per.Age) is the tuple literal; the method returns the first, middle,
and last name, along with the age, of a PersonInfo object.
public (string, string, string, int) GetPersonalInfo(string id)
{
PersonInfo per = PersonInfo.RetrieveInfoById(id);
return (per.FirstName, per.MiddleName, per.LastName, per.Age);
}
The caller can then consume the returned tuple with code like the following:
Names can also be assigned to the tuple elements in the tuple type definition. The following example shows an
alternate version of the GetPersonalInfo method that uses named elements:
public (string FName, string MName, string LName, int Age) GetPersonalInfo(string id)
{
PersonInfo per = PersonInfo.RetrieveInfoById(id);
return (per.FirstName, per.MiddleName, per.LastName, per.Age);
}
The previous call to the GetPersonInfo method can then be modified as follows:
If a method is passed an array as an argument and modifies the value of individual elements, it is not necessary for
the method to return the array, although you may choose to do so for good style or functional flow of values. This
is because C# passes all reference types by value, and the value of an array reference is the pointer to the array. In
the following example, changes to the contents of the values array that are made in the DoubleValues method are
observable by any code that has a reference to the array.
using System;
Extension methods
Ordinarily, there are two ways to add a method to an existing type:
Modify the source code for that type. You cannot do this, of course, if you do not own the type's source code.
And this becomes a breaking change if you also add any private data fields to support the method.
Define the new method in a derived class. A method cannot be added in this way using inheritance for other
types, such as structures and enumerations. Nor can it be used to "add" a method to a sealed class.
Extension methods let you "add" a method to an existing type without modifying the type itself or implementing
the new method in an inherited type. The extension method also does not have to reside in the same assembly as
the type it extends. You call an extension method as if it were a defined member of a type.
For more information, see Extension Methods.
Async Methods
By using the async feature, you can invoke asynchronous methods without using explicit callbacks or manually
splitting your code across multiple methods or lambda expressions.
If you mark a method with the async modifier, you can use the await operator in the method. When control reaches
an await expression in the async method, control returns to the caller if the awaited task is not completed, and
progress in the method with the await keyword is suspended until the awaited task completes. When the task is
complete, execution can resume in the method.
NOTE
An async method returns to the caller when either it encounters the first awaited object that's not yet complete or it gets to
the end of the async method, whichever occurs first.
An async method can have a return type of Task<TResult>, Task, or void . The void return type is used primarily
to define event handlers, where a void return type is required. An async method that returns void can't be
awaited, and the caller of a void-returning method can't catch exceptions that the method throws. Starting with C#
7.0, an async method can have any task-like return type.
In the following example, DelayAsync is an async method that has a return statement that returns an integer.
Because it is an async method, its method declaration must have a return type of Task<int> . Because the return
type is Task<int> , the evaluation of the await expression in DoSomethingAsync produces an integer, as the
following int result = await delayTask statement demonstrates.
using System;
using System.Threading.Tasks;
class Program
{
static Task Main() => DoSomethingAsync();
Console.WriteLine($"Result: {result}");
}
An async method can't declare any in, ref, or out parameters, but it can call methods that have such parameters.
For more information about async methods, see Asynchronous programming with async and await and Async
return types.
Expression-bodied members
It is common to have method definitions that simply return immediately with the result of an expression, or that
have a single statement as the body of the method. There is a syntax shortcut for defining such methods using => :
public Point Move(int dx, int dy) => new Point(x + dx, y + dy);
public void Print() => Console.WriteLine(First + " " + Last);
// Works with operators, properties, and indexers too.
public static Complex operator +(Complex a, Complex b) => a.Add(b);
public string Name => First + " " + Last;
public Customer this[long id] => store.LookupCustomer(id);
If the method returns void or is an async method, the body of the method must be a statement expression (same
as with lambdas). For properties and indexers, they must be read-only, and you do not use the get accessor
keyword.
Iterators
An iterator performs a custom iteration over a collection, such as a list or an array. An iterator uses the yield return
statement to return each element one at a time. When a yield return statement is reached, the current location is
remembered so that the caller can request the next element in the sequence.
The return type of an iterator can be IEnumerable, IEnumerable<T>, IEnumerator, or IEnumerator<T>.
For more information, see Iterators.
See also
Access Modifiers
Static Classes and Static Class Members
Inheritance
Abstract and Sealed Classes and Class Members
params
out
ref
in
Passing Parameters
Properties
9/3/2020 • 9 minutes to read • Edit Online
Properties are first class citizens in C#. The language defines syntax that enables developers to write code that
accurately expresses their design intent.
Properties behave like fields when they are accessed. However, unlike fields, properties are implemented with
accessors that define the statements executed when a property is accessed or assigned.
Property syntax
The syntax for properties is a natural extension to fields. A field defines a storage location:
A property definition contains declarations for a get and set accessor that retrieves and assigns the value of
that property:
The syntax shown above is the auto property syntax. The compiler generates the storage location for the field that
backs up the property. The compiler also implements the body of the get and set accessors.
Sometimes, you need to initialize a property to a value other than the default for its type. C# enables that by
setting a value after the closing brace for the property. You may prefer the initial value for the FirstName property
to be the empty string rather than null . You would specify that as shown below:
Specific initialization is most useful for read-only properties, as you'll see later in this article.
You can also define the storage yourself, as shown below:
public class Person
{
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}
private string firstName;
// remaining implementation removed from listing
}
When a property implementation is a single expression, you can use expression-bodied members for the getter or
setter:
This simplified syntax will be used where applicable throughout this article.
The property definition shown above is a read-write property. Notice the keyword value in the set accessor. The
set accessor always has a single parameter named value . The get accessor must return a value that is
convertible to the type of the property ( string in this example).
That's the basics of the syntax. There are many different variations that support a variety of different design
idioms. Let's explore, and learn the syntax options for each.
Scenarios
The examples above showed one of the simplest cases of property definition: a read-write property with no
validation. By writing the code you want in the get and set accessors, you can create many different scenarios.
Validation
You can write code in the set accessor to ensure that the values represented by a property are always valid. For
example, suppose one rule for the Person class is that the name cannot be blank or white space. You would write
that as follows:
public class Person
{
public string FirstName
{
get => firstName;
set
{
if (string.IsNullOrWhiteSpace(value))
throw new ArgumentException("First name must not be blank");
firstName = value;
}
}
private string firstName;
// remaining implementation removed from listing
}
The preceding example can be simplified by using a throw expression as part of the property setter validation:
The example above enforces the rule that the first name must not be blank or white space. If a developer writes
hero.FirstName = "";
That assignment throws an ArgumentException . Because a property set accessor must have a void return type, you
report errors in the set accessor by throwing an exception.
You can extend this same syntax to anything needed in your scenario. You can check the relationships between
different properties, or validate against any external conditions. Any valid C# statements are valid in a property
accessor.
Read-only
Up to this point, all the property definitions you have seen are read/write properties with public accessors. That's
not the only valid accessibility for properties. You can create read-only properties, or give different accessibility to
the set and get accessors. Suppose that your Person class should only enable changing the value of the
FirstName property from other methods in that class. You could give the set accessor private accessibility
instead of public :
Now, the FirstName property can be accessed from any code, but it can only be assigned from other code in the
Person class.
You can add any restrictive access modifier to either the set or get accessors. Any access modifier you place on the
individual accessor must be more limited than the access modifier on the property definition. The above is legal
because the FirstName property is public , but the set accessor is private . You could not declare a private
property with a public accessor. Property declarations can also be declared protected , internal ,
protected internal , or, even private .
It is also legal to place the more restrictive modifier on the get accessor. For example, you could have a public
property, but restrict the get accessor to private . That scenario is rarely done in practice.
You can also restrict modifications to a property so that it can only be set in a constructor or a property initializer.
You can modify the Person class so as follows:
This feature is most commonly used for initializing collections that are exposed as read-only properties:
Computed properties
A property does not need to simply return the value of a member field. You can create properties that return a
computed value. Let's expand the Person object to return the full name, computed by concatenating the first and
last names:
The example above uses the string interpolation feature to create the formatted string for the full name.
You can also use an expression-bodied member, which provides a more succinct way to create the computed
FullName property:
Expression-bodied members use the lambda expression syntax to define methods that contain a single expression.
Here, that expression returns the full name for the person object.
Cached evaluated properties
You can mix the concept of a computed property with storage and create a cached evaluated property. For
example, you could update the FullName property so that the string formatting only happened the first time it was
accessed:
The above code contains a bug though. If code updates the value of either the FirstName or LastName property,
the previously evaluated fullName field is invalid. You modify the set accessors of the FirstName and LastName
property so that the fullName field is calculated again:
public class Person
{
private string firstName;
public string FirstName
{
get => firstName;
set
{
firstName = value;
fullName = null;
}
}
This final version evaluates the FullName property only when needed. If the previously calculated version is valid,
it's used. If another state change invalidates the previously calculated version, it will be recalculated. Developers
that use this class do not need to know the details of the implementation. None of these internal changes affect
the use of the Person object. That's the key reason for using Properties to expose data members of an object.
Attaching attributes to auto -implemented properties
Beginning with C# 7.3, field attributes can be attached to the compiler generated backing field in auto-
implemented properties. For example, consider a revision to the Person class that adds a unique integer Id
property. You write the Id property using an auto-implemented property, but your design does not call for
persisting the Id property. The NonSerializedAttribute can only be attached to fields, not properties. You can
attach the NonSerializedAttribute to the backing field for the Id property by using the field: specifier on the
attribute, as shown in the following example:
[field:NonSerialized]
public int Id { get; set; }
The ?. operator is called the null conditional operator. It checks for a null reference before evaluating the right
side of the operator. The end result is that if there are no subscribers to the PropertyChanged event, the code to
raise the event doesn't execute. It would throw a NullReferenceException without this check in that case. For more
information, see events . This example also uses the new nameof operator to convert from the property name
symbol to its text representation. Using nameof can reduce errors where you have mistyped the name of the
property.
Again, implementing INotifyPropertyChanged is an example of a case where you can write code in your accessors
to support the scenarios you need.
Summing up
Properties are a form of smart fields in a class or object. From outside the object, they appear like fields in the
object. However, properties can be implemented using the full palette of C# functionality. You can provide
validation, different accessibility, lazy evaluation, or any requirements your scenarios need.
Indexers
9/3/2020 • 9 minutes to read • Edit Online
Indexers are similar to properties. In many ways indexers build on the same language features as properties.
Indexers enable indexed properties: properties referenced using one or more arguments. Those arguments provide
an index into some collection of values.
Indexer Syntax
You access an indexer through a variable name and square brackets. You place the indexer arguments inside the
brackets:
You declare indexers using the this keyword as the property name, and declaring the arguments within square
brackets. This declaration would match the usage shown in the previous paragraph:
From this initial example, you can see the relationship between the syntax for properties and for indexers. This
analogy carries through most of the syntax rules for indexers. Indexers can have any valid access modifiers (public,
protected internal, protected, internal, private or private protected). They may be sealed, virtual, or abstract. As with
properties, you can specify different access modifiers for the get and set accessors in an indexer. You may also
specify read-only indexers (by omitting the set accessor), or write-only indexers (by omitting the get accessor).
You can apply almost everything you learn from working with properties to indexers. The only exception to that
rule is auto implemented properties. The compiler cannot always generate the correct storage for an indexer.
The presence of arguments to reference an item in a set of items distinguishes indexers from properties. You may
define multiple indexers on a type, as long as the argument lists for each indexer is unique. Let's explore different
scenarios where you might use one or more indexers in a class definition.
Scenarios
You would define indexers in your type when its API models some collection where you define the arguments to
that collection. Your indexers may or may not map directly to the collection types that are part of the .NET core
framework. Your type may have other responsibilities in addition to modeling a collection. Indexers enable you to
provide the API that matches your type's abstraction without exposing the inner details of how the values for that
abstraction are stored or computed.
Let's walk through some of the common scenarios for using indexers. You can access the sample folder for
indexers. For download instructions, see Samples and Tutorials.
Arrays and Vectors
One of the most common scenarios for creating indexers is when your type models an array, or a vector. You can
create an indexer to model an ordered list of data.
The advantage of creating your own indexer is that you can define the storage for that collection to suit your needs.
Imagine a scenario where your type models historical data that is too large to load into memory at once. You need
to load and unload sections of the collection based on usage. The example following models this behavior. It reports
on how many data points exist. It creates pages to hold sections of the data on demand. It removes pages from
memory to make room for pages needed by more recent requests.
page[index] = value;
}
}
You can follow this design idiom to model any sort of collection where there are good reasons not to load the
entire set of data into an in- memory collection. Notice that the Page class is a private nested class that is not part
of the public interface. Those details are hidden from any users of this class.
Dictionaries
Another common scenario is when you need to model a dictionary or a map. This scenario is when your type stores
values based on key, typically text keys. This example creates a dictionary that maps command line arguments to
lambda expressions that manage those options. The following example shows two classes: an ArgsActions class
that maps a command line option to an Action delegate, and an ArgsProcessor that uses the ArgsActions to
execute each Action when it encounters that option.
}
public class ArgsActions
{
readonly private Dictionary<string, Action> argsActions = new Dictionary<string, Action>();
In this example, the ArgsAction collection maps closely to the underlying collection. The get determines if a given
option has been configured. If so, it returns the Action associated with that option. If not, it returns an Action that
does nothing. The public accessor does not include a set accessor. Rather, the design using a public method for
setting options.
Multi-Dimensional Maps
You can create indexers that use multiple arguments. In addition, those arguments are not constrained to be the
same type. Let's look at two examples.
The first example shows a class that generates values for a Mandelbrot set. For more information on the
mathematics behind the set, read this article. The indexer uses two doubles to define a point in the X, Y plane. The
get accessor computes the number of iterations until a point is determined to be not in the set. If the maximum
iterations is reached, the point is in the set, and the class's maxIterations value is returned. (The computer generated
images popularized for the Mandelbrot set define colors for the number of iterations necessary to determine that a
point is outside the set.
public class Mandelbrot
{
readonly private int maxIterations;
The Mandelbrot Set defines values at every (x,y) coordinate for real number values. That defines a dictionary that
could contain an infinite number of values. Therefore, there is no storage behind the set. Instead, this class
computes the value for each point when code calls the get accessor. There's no underlying storage used.
Let's examine one last use of indexers, where the indexer takes multiple arguments of different types. Consider a
program that manages historical temperature data. This indexer uses a city and a date to set or get the high and
low temperatures for that location:
using DateMeasurements =
System.Collections.Generic.Dictionary<System.DateTime, IndexersSamples.Common.Measurements>;
using CityDataMeasurements =
System.Collections.Generic.Dictionary<string, System.Collections.Generic.Dictionary<System.DateTime,
IndexersSamples.Common.Measurements>>;
This example creates an indexer that maps weather data on two different arguments: a city (represented by a
string ) and a date (represented by a DateTime ). The internal storage uses two Dictionary classes to represent
the two-dimensional dictionary. The public API no longer represents the underlying storage. Rather, the language
features of indexers enables you to create a public interface that represents your abstraction, even though the
underlying storage must use different core collection types.
There are two parts of this code that may be unfamiliar to some developers. These two using directives:
create an alias for a constructed generic type. Those statements enable the code later to use the more descriptive
DateMeasurements and CityDateMeasurements names instead of the generic construction of
Dictionary<DateTime, Measurements> and Dictionary<string, Dictionary<DateTime, Measurements> > . This construct
does require using the fully qualified type names on the right side of the = sign.
The second technique is to strip off the time portions of any DateTime object used to index into the collections.
.NET doesn't include a date-only type. Developers use the DateTime type, but use the Date property to ensure that
any DateTime object from that day are equal.
Summing Up
You should create indexers anytime you have a property-like element in your class where that property represents
not a single value, but rather a collection of values where each individual item is identified by a set of arguments.
Those arguments can uniquely identify which item in the collection should be referenced. Indexers extend the
concept of properties, where a member is treated like a data item from outside the class, but like a method on the
inside. Indexers allow arguments to find a single item in a property that represents a set of items.
Discards - C# Guide
10/30/2019 • 7 minutes to read • Edit Online
Starting with C# 7.0, C# supports discards, which are temporary, dummy variables that are intentionally unused in
application code. Discards are equivalent to unassigned variables; they do not have a value. Because there is only a
single discard variable, and that variable may not even be allocated storage, discards can reduce memory
allocations. Because they make the intent of your code clear, they enhance its readability and maintainability.
You indicate that a variable is a discard by assigning it the underscore ( _ ) as its name. For example, the following
method call returns a 3-tuple in which the first and second values are discards and area is a previously declared
variable to be set to the corresponding third component returned by GetCityInformation:
private static (string, double, int, int, int, int) QueryCityDataForYears(string name, int year1, int
year2)
{
int population1 = 0, population2 = 0;
double area = 0;
For more information on deconstructing tuples with discards, see Deconstructing tuples and other types.
The Deconstruct method of a class, structure, or interface also allows you to retrieve and deconstruct a specific set
of data from an object. You can use discards when you are interested in working with only a subset of the
deconstructed values. The following example deconstructs a Person object into four strings (the first and last
names, the city, and the state), but discards the last name and the state.
using System;
public void Deconstruct(out string fname, out string mname, out string lname)
{
fname = FirstName;
mname = MiddleName;
lname = LastName;
}
// <Snippet1>
// Deconstruct the person object.
var (fName, _, city, _) = p;
Console.WriteLine($"Hello {fName} of {city}!");
// The example displays the following output:
// Hello John of Boston!
// </Snippet1>
}
}
// The example displays the following output:
// Hello John Adams of Boston, MA!
For more information on deconstructing user-defined types with discards, see Deconstructing tuples and other
types.
Pattern matching with switch and is
The discard pattern can be used in pattern matching with the is and switch keywords. Every expression always
matches the discard pattern.
The following example defines a ProvidesFormatInfo method that uses is statements to determine whether an
object provides an IFormatProvider implementation and tests whether the object is null . It also uses the discard
pattern to handle non-null objects of any other type.
using System;
using System.Globalization;
A standalone discard
You can use a standalone discard to indicate any variable that you choose to ignore. The following example uses a
standalone discard to ignore the Task object returned by an asynchronous operation. This has the effect of
suppressing the exception that the operation throws as it is about to complete.
using System;
using System.Threading.Tasks;
Compiler error CS0136, "A local or parameter named '_' cannot be declared in this scope because that name
is used in an enclosing local scope to define a local or parameter." For example:
See also
Deconstructing tuples and other types
is keyword
switch keyword
Generics (C# Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
Generics introduce the concept of type parameters to .NET, which make it possible to design classes and methods
that defer the specification of one or more types until the class or method is declared and instantiated by client
code. For example, by using a generic type parameter T , you can write a single class that other client code can use
without incurring the cost or risk of runtime casts or boxing operations, as shown here:
Generic classes and methods combine reusability, type safety, and efficiency in a way that their non-generic
counterparts cannot. Generics are most frequently used with collections and the methods that operate on them. The
System.Collections.Generic namespace contains several generic-based collection classes. The non-generic
collections, such as ArrayList are not recommended and are maintained for compatibility purposes. For more
information, see Generics in .NET.
Of course, you can also create custom generic types and methods to provide your own generalized solutions and
design patterns that are type-safe and efficient. The following code example shows a simple generic linked-list class
for demonstration purposes. (In most cases, you should use the List<T> class provided by .NET instead of creating
your own.) The type parameter T is used in several locations where a concrete type would ordinarily be used to
indicate the type of the item stored in the list. It is used in the following ways:
As the type of a method parameter in the AddHead method.
As the return type of the Data property in the nested Node class.
As the type of the private member data in the nested class.
Note that T is available to the nested Node class. When GenericList<T> is instantiated with a concrete type, for
example as a GenericList<int> , each occurrence of T will be replaced with int .
// type parameter T in angle brackets
public class GenericList<T>
{
// The nested class is also generic on T.
private class Node
{
// T used in non-generic constructor.
public Node(T t)
{
next = null;
data = t;
}
// constructor
public GenericList()
{
head = null;
}
The following code example shows how client code uses the generic GenericList<T> class to create a list of
integers. Simply by changing the type argument, the following code could easily be modified to create lists of
strings or any other custom type:
class TestGenericList
{
static void Main()
{
// int is the type argument
GenericList<int> list = new GenericList<int>();
Generics overview
Use generic types to maximize code reuse, type safety, and performance.
The most common use of generics is to create collection classes.
The .NET class library contains several generic collection classes in the System.Collections.Generic namespace.
These should be used whenever possible instead of classes such as ArrayList in the System.Collections
namespace.
You can create your own generic interfaces, classes, methods, events, and delegates.
Generic classes may be constrained to enable access to methods on particular data types.
Information on the types that are used in a generic data type may be obtained at run-time by using reflection.
Related sections
Generic Type Parameters
Constraints on Type Parameters
Generic Classes
Generic Interfaces
Generic Methods
Generic Delegates
Differences Between C++ Templates and C# Generics
Generics and Reflection
Generics in the Run Time
C# language specification
For more information, see the C# Language Specification.
See also
System.Collections.Generic
C# Programming Guide
Types
<typeparam>
<typeparamref>
Generics in .NET
Iterators
9/3/2020 • 5 minutes to read • Edit Online
Almost every program you write will have some need to iterate over a collection. You'll write code that examines
every item in a collection.
You'll also create iterator methods which are methods that produces an iterator (which is an object that traverses a
container, particularly lists) for the elements of that class. These can be used for:
Performing an action on each item in a collection.
Enumerating a custom collection.
Extending LINQ or other libraries.
Creating a data pipeline where data flows efficiently through iterator methods.
The C# language provides features for both these scenarios. This article provides an overview of those features.
This tutorial has multiple steps. After each step, you can run the application and see the progress. You can also view
or download the completed sample for this topic. For download instructions, see Samples and Tutorials.
That's all there is to it. To iterate over all the contents of a collection, the foreach statement is all you need. The
foreach statement isn't magic, though. It relies on two generic interfaces defined in the .NET core library in order
to generate the code necessary to iterate a collection: IEnumerable<T> and IEnumerator<T> . This mechanism is
explained in more detail below.
Both of these interfaces also have non-generic counterparts: IEnumerable and IEnumerator . The generic versions
are preferred for modern code.
The code above shows distinct yield return statements to highlight the fact that you can use multiple discrete
yield return statements in an iterator method. You can (and often do) use other language constructs to simplify
the code of an iterator method. The method definition below produces the exact same sequence of numbers:
You don't have to decide one or the other. You can have as many yield return statements as necessary to meet
the needs of your method:
index = 100;
while (index < 110)
yield return index++;
}
That's the basic syntax. Let's consider a real world example where you would write an iterator method. Imagine
you're on an IoT project and the device sensors generate a very large stream of data. To get a feel for the data, you
might write a method that samples every Nth data element. This small iterator method does the trick:
There is one important restriction on iterator methods: you can't have both a return statement and a
yield return statement in the same method. The following will not compile:
public IEnumerable<int> GetSingleDigitNumbers()
{
int index = 0;
while (index < 10)
yield return index++;
This restriction normally isn't a problem. You have a choice of either using yield return throughout the method,
or separating the original method into multiple methods, some using return , and some using yield return .
You can modify the last method slightly to use yield return everywhere:
var items = new int[] {100, 101, 102, 103, 104, 105, 106, 107, 108, 109 };
foreach (var item in items)
yield return item;
}
Sometimes, the right answer is to split an iterator method into two different methods. One that uses return , and a
second that uses yield return . Consider a situation where you might want to return an empty collection, or the
first 5 odd numbers, based on a boolean argument. You could write that as these two methods:
Look at the methods above. The first uses the standard return statement to return either an empty collection, or
the iterator created by the second method. The second method uses the yield return statement to create the
requested sequence.
The construct above represents the code generated by the C# compiler as of version 5 and above. Prior to version
5, the item variable had a different scope:
// C# versions 1 through 4:
IEnumerator<int> enumerator = collection.GetEnumerator();
int item = default(int);
while (enumerator.MoveNext())
{
item = enumerator.Current;
Console.WriteLine(item.ToString());
}
This was changed because the earlier behavior could lead to subtle and hard to diagnose bugs involving lambda
expressions. For more information about lambda expressions, see Lambda expressions.
The exact code generated by the compiler is somewhat more complicated, and handles situations where the object
returned by GetEnumerator() implements the IDisposable interface. The full expansion generates code more like
this:
{
var enumerator = collection.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
var item = enumerator.Current;
Console.WriteLine(item.ToString());
}
} finally
{
// dispose of enumerator.
}
}
The manner in which the enumerator is disposed of depends on the characteristics of the type of enumerator . In
the general case, the finally clause expands to:
finally
{
(enumerator as IDisposable)?.Dispose();
}
However, if the type of enumerator is a sealed type and there is no implicit conversion from the type of enumerator
to IDisposable , the finally clause expands to an empty block:
finally
{
}
If there is an implicit conversion from the type of enumerator to IDisposable , and enumerator is a non-nullable
value type, the finally clause expands to:
finally
{
((IDisposable)enumerator).Dispose();
}
Thankfully, you don't need to remember all these details. The foreach statement handles all those nuances for you.
The compiler will generate the correct code for any of these constructs.
Introduction to Delegates
3/12/2020 • 2 minutes to read • Edit Online
Delegates provide a late binding mechanism in .NET. Late Binding means that you create an algorithm where the
caller also supplies at least one method that implements part of the algorithm.
For example, consider sorting a list of stars in an astronomy application. You may choose to sort those stars by
their distance from the earth, or the magnitude of the star, or their perceived brightness.
In all those cases, the Sort() method does essentially the same thing: arranges the items in the list based on some
comparison. The code that compares two stars is different for each of the sort orderings.
These kinds of solutions have been used in software for half a century. The C# language delegate concept provides
first class language support, and type safety around the concept.
As you'll see later in this series, the C# code you write for algorithms like this is type safe, and leverages the
language and the compiler to ensure that the types match for arguments and return types.
Previous
This article covers the classes in .NET that support delegates, and how those map to the delegate keyword.
The compiler generates a class, derived from System.Delegate that matches the signature used (in this case, a
method that returns an integer, and has two arguments). The type of that delegate is Comparison . The Comparison
delegate type is a generic type. For details on generics see here.
Notice that the syntax may appear as though it is declaring a variable, but it is actually declaring a type. You can
define delegate types inside classes, directly inside namespaces, or even in the global namespace.
NOTE
Declaring delegate types (or other types) directly in the global namespace is not recommended.
The compiler also generates add and remove handlers for this new type so that clients of this class can add and
remove methods from an instance's invocation list. The compiler will enforce that the signature of the method
being added or removed matches the signature used when declaring the method.
The type of the variable is Comparison<T> , the delegate type defined earlier. The name of the variable is comparator
.
That code snippet above declared a member variable inside a class. You can also declare delegate variables that are
local variables, or arguments to methods.
Invoke delegates
You invoke the methods that are in the invocation list of a delegate by calling that delegate. Inside the Sort()
method, the code will call the comparison method to determine which order to place objects:
In the line above, the code invokes the method attached to the delegate. You treat the variable as a method name,
and invoke it using normal method call syntax.
That line of code makes an unsafe assumption: There's no guarantee that a target has been added to the delegate.
If no targets have been attached, the line above would cause a NullReferenceException to be thrown. The idioms
used to address this problem are more complicated than a simple null-check, and are covered later in this series.
The method is declared as a private method. That's fine. You may not want this method to be part of your public
interface. It can still be used as the comparison method when attached to a delegate. The calling code will have this
method attached to the target list of the delegate object, and can access it through that delegate.
You create that relationship by passing that method to the List.Sort() method:
phrases.Sort(CompareLength);
Notice that the method name is used, without parentheses. Using the method as an argument tells the compiler to
convert the method reference into a reference that can be used as a delegate invocation target, and attach that
method as an invocation target.
You could also have been explicit by declaring a variable of type Comparison<string> and doing an assignment:
In uses where the method being used as a delegate target is a small method, it's common to use lambda
expression syntax to perform the assignment:
Previous
In the previous article, you saw that you create specific delegate types using the delegate keyword.
The abstract Delegate class provide the infrastructure for loose coupling and invocation. Concrete Delegate types
become much more useful by embracing and enforcing type safety for the methods that are added to the
invocation list for a delegate object. When you use the delegate keyword and define a concrete delegate type, the
compiler generates those methods.
In practice, this would lead to creating new delegate types whenever you need a different method signature. This
work could get tedious after a time. Every new feature requires new delegate types.
Thankfully, this isn't necessary. The .NET Core framework contains several types that you can reuse whenever you
need delegate types. These are generic definitions so you can declare customizations when you need new method
declarations.
The first of these types is the Action type, and several variations:
The in modifier on the generic type argument is covered in the article on covariance.
There are variations of the Action delegate that contain up to 16 arguments such as
Action<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16>. It's important that these definitions use different
generic arguments for each of the delegate arguments: That gives you maximum flexibility. The method arguments
need not be, but may be, the same type.
Use one of the Action types for any delegate type that has a void return type.
The framework also includes several generic delegate types that you can use for delegate types that return values:
The out modifier on the result generic type argument is covered in the article on covariance.
There are variations of the Func delegate with up to 16 input arguments such as
Func<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,TResult>. The type of the result is always the last
type parameter in all the Func declarations, by convention.
Use one of the Func types for any delegate type that returns a value.
There's also a specialized Predicate<T> type for a delegate that returns a test on a single value:
You might think these two types are equivalent. They are not. These two variables cannot be used interchangeably.
A variable of one type cannot be assigned the other type. The C# type system uses the names of the defined types,
not the structure.
All these delegate type definitions in the .NET Core Library should mean that you do not need to define a new
delegate type for any new feature you create that requires delegates. These generic definitions should provide all
the delegate types you need under most situations. You can simply instantiate one of these types with the required
type parameters. In the case of algorithms that can be made generic, these delegates can be used as generic types.
This should save time, and minimize the number of new types that you need to create in order to work with
delegates.
In the next article, you'll see several common patterns for working with delegates in practice.
Next
Common Patterns for Delegates
3/12/2020 • 8 minutes to read • Edit Online
Previous
Delegates provide a mechanism that enables software designs involving minimal coupling between components.
One excellent example for this kind of design is LINQ. The LINQ Query Expression Pattern relies on delegates for
all of its features. Consider this simple example:
This filters the sequence of numbers to only those less than the value 10. The Where method uses a delegate that
determines which elements of a sequence pass the filter. When you create a LINQ query, you supply the
implementation of the delegate for this specific purpose.
The prototype for the Where method is:
This example is repeated with all the methods that are part of LINQ. They all rely on delegates for the code that
manages the specific query. This API design pattern is a very powerful one to learn and understand.
This simple example illustrates how delegates require very little coupling between components. You don't need to
create a class that derives from a particular base class. You don't need to implement a specific interface. The only
requirement is to provide the implementation of one method that is fundamental to the task at hand.
The static class above is the simplest thing that can work. We need to write the single implementation for the
method that writes messages to the console:
Finally, you need to hook up the delegate by attaching it to the WriteMessage delegate declared in the logger:
Logger.WriteMessage += LoggingMethods.LogToConsole;
Practices
Our sample so far is fairly simple, but it still demonstrates some of the important guidelines for designs involving
delegates.
Using the delegate types defined in the Core Framework makes it easier for users to work with the delegates. You
don't need to define new types, and developers using your library do not need to learn new, specialized delegate
types.
The interfaces used are as minimal and as flexible as possible: To create a new output logger, you must create one
method. That method may be a static method, or an instance method. It may have any access.
Formatting Output
Let's make this first version a bit more robust, and then start creating other logging mechanisms.
Next, let's add a few arguments to the LogMessage() method so that your log class creates more structured
messages:
public enum Severity
{
Verbose,
Trace,
Information,
Warning,
Error,
Critical
}
Next, let's make use of that Severity argument to filter the messages that are sent to the log's output.
Practices
You've added new features to the logging infrastructure. Because the logger component is very loosely coupled to
any output mechanism, these new features can be added with no impact on any of the code implementing the
logger delegate.
As you keep building this, you'll see more examples of how this loose coupling enables greater flexibility in
updating parts of the site without any changes to other locations. In fact, in a larger application, the logger output
classes might be in a different assembly, and not even need to be rebuilt.
Once you've created this class, you can instantiate it and it attaches its LogMessage method to the Logger
component:
These two are not mutually exclusive. You could attach both log methods and generate messages to the console
and a file:
Later, even in the same application, you can remove one of the delegates without any other issues to the system:
Logger.WriteMessage -= LoggingMethods.LogToConsole;
Practices
Now, you've added a second output handler for the logging sub-system. This one needs a bit more infrastructure
to correctly support the file system. The delegate is an instance method. It's also a private method. There's no need
for greater accessibility because the delegate infrastructure can connect the delegates.
Second, the delegate-based design enables multiple output methods without any extra code. You don't need to
build any additional infrastructure to support multiple output methods. They simply become another method on
the invocation list.
Pay special attention to the code in the file logging output method. It is coded to ensure that it does not throw any
exceptions. While this isn't always strictly necessary, it's often a good practice. If either of the delegate methods
throws an exception, the remaining delegates that are on the invocation won't be invoked.
As a last note, the file logger must manage its resources by opening and closing the file on each log message. You
could choose to keep the file open and implement IDisposable to close the file when you are completed. Either
method has its advantages and disadvantages. Both do create a bit more coupling between the classes.
None of the code in the Logger class would need to be updated in order to support either scenario.
The null conditional operator ( ?. ) short-circuits when the left operand ( WriteMessage in this case) is null, which
means no attempt is made to log a message.
You won't find the Invoke() method listed in the documentation for System.Delegate or
System.MulticastDelegate . The compiler generates a type safe Invoke method for any delegate type declared. In
this example, that means Invoke takes a single string argument, and has a void return type.
Summary of Practices
You've seen the beginnings of a log component that could be expanded with other writers, and other features. By
using delegates in the design these different components are very loosely coupled. This provides several
advantages. It's very easy to create new output mechanisms and attach them to the system. These other
mechanisms only need one method: the method that writes the log message. It's a design that is very resilient
when new features are added. The contract required for any writer is to implement one method. That method
could be a static or instance method. It could be public, private, or any other legal access.
The Logger class can make any number of enhancements or changes without introducing breaking changes. Like
any class, you cannot modify the public API without the risk of breaking changes. But, because the coupling
between the logger and any output engines is only through the delegate, no other types (like interfaces or base
classes) are involved. The coupling is as small as possible.
Next
Introduction to events
3/12/2020 • 3 minutes to read • Edit Online
Previous
Events are, like delegates, a late binding mechanism. In fact, events are built on the language support for delegates.
Events are a way for an object to broadcast (to all interested components in the system) that something has
happened. Any other component can subscribe to the event, and be notified when an event is raised.
You've probably used events in some of your programming. Many graphical systems have an event model to
report user interaction. These events would report mouse movement, button presses and similar interactions.
That's one of the most common, but certainly not the only scenario where events are used.
You can define events that should be raised for your classes. One important consideration when working with
events is that there may not be any object registered for a particular event. You must write your code so that it
does not raise events when no listeners are configured.
Subscribing to an event also creates a coupling between two objects (the event source, and the event sink). You
need to ensure that the event sink unsubscribes from the event source when no longer interested in events.
The type of the event ( EventHandler<FileListArgs> in this example) must be a delegate type. There are a number of
conventions that you should follow when declaring an event. Typically, the event delegate type has a void return.
Event declarations should be a verb, or a verb phrase. Use past tense when the event reports something that has
happened. Use a present tense verb (for example, Closing ) to report something that is about to happen. Often,
using present tense indicates that your class supports some kind of customization behavior. One of the most
common scenarios is to support cancellation. For example, a Closing event may include an argument that would
indicate if the close operation should continue, or not. Other scenarios may enable callers to modify behavior by
updating properties of the event arguments. You may raise an event to indicate a proposed next action an
algorithm will take. The event handler may mandate a different action by modifying properties of the event
argument.
When you want to raise the event, you call the event handlers using the delegate invocation syntax:
As discussed in the section on delegates, the ?. operator makes it easy to ensure that you do not attempt to raise
the event when there are no subscribers to that event.
You subscribe to an event by using the += operator:
fileLister.Progress += onProgress;
The handler method typically has the prefix 'On' followed by the event name, as shown above.
You unsubscribe using the -= operator:
fileLister.Progress -= onProgress;
It's important to note that I declared a local variable for the expression that represents the event handler. That
ensures the unsubscribe removes the handler. If, instead, you used the body of the lambda expression, you are
attempting to remove a handler that has never been attached, which does nothing.
In the next article, you'll learn more about typical event patterns, and different variations on this example.
Next
Standard .NET event patterns
3/12/2020 • 8 minutes to read • Edit Online
Previous
.NET events generally follow a few known patterns. Standardizing on these patterns means that developers can
leverage knowledge of those standard patterns, which can be applied to any .NET event program.
Let's go through these standard patterns so you will have all the knowledge you need to create standard event
sources, and subscribe and process standard events in your code.
The return type is void. Events are based on delegates and are multicast delegates. That supports multiple
subscribers for any event source. The single return value from a method doesn't scale to multiple event
subscribers. Which return value does the event source see after raising an event? Later in this article you'll see how
to create event protocols that support event subscribers that report information to the event source.
The argument list contains two arguments: the sender, and the event arguments. The compile time type of sender
is System.Object , even though you likely know a more derived type that would always be correct. By convention,
use object .
The second argument has typically been a type that is derived from System.EventArgs . (You'll see in the next
section that this convention is no longer enforced.) If your event type does not need any additional arguments, you
will still provide both arguments. There is a special value, EventArgs.Empty that you should use to denote that your
event does not contain any additional information.
Let's build a class that lists files in a directory, or any of its subdirectories that follow a pattern. This component
raises an event for each file found that matches the pattern.
Using an event model provides some design advantages. You can create multiple event listeners that perform
different actions when a sought file is found. Combining the different listeners can create more robust algorithms.
Here is the initial event argument declaration for finding a sought file:
Even though this type looks like a small, data-only type, you should follow the convention and make it a reference (
class ) type. That means the argument object will be passed by reference, and any updates to the data will be
viewed by all subscribers. The first version is an immutable object. You should prefer to make the properties in
your event argument type immutable. That way, one subscriber cannot change the values before another
subscriber sees them. (There are exceptions to this, as you'll see below.)
Next, we need to create the event declaration in the FileSearcher class. Leveraging the EventHandler<T> type means
that you don't need to create yet another type definition. You simply use a generic specialization.
Let's fill out the FileSearcher class to search for files that match a pattern, and raise the correct event when a match
is discovered.
This looks like it's declaring a public field, which would appear to be bad object-oriented practice. You want to
protect data access through properties, or methods. While this may look like a bad practice, the code generated by
the compiler does create wrappers so that the event objects can only be accessed in safe ways. The only operations
available on a field-like event are add handler:
fileLister.FileFound += onFileFound;
fileLister.FileFound -= onFileFound;
Note that there's a local variable for the handler. If you used the body of the lambda, the remove would not work
correctly. It would be a different instance of the delegate, and silently do nothing.
Code outside the class cannot raise the event, nor can it perform any other operations.
This new Field is automatically initialized to false , the default value for a Boolean field, so you don't cancel
accidentally. The only other change to the component is to check the flag after raising the event to see if any of the
subscribers have requested a cancellation:
One advantage of this pattern is that it isn't a breaking change. None of the subscribers requested a cancellation
before, and they still are not. None of the subscriber code needs updating unless they want to support the new
cancel protocol. It's very loosely coupled.
Let's update the subscriber so that it requests a cancellation once it finds the first executable:
This could get to be a lengthy operation in a directory with many sub-directories. Let's add an event that gets
raised when each new directory search begins. This enables subscribers to track progress, and update the user as
to progress. All the samples you've created so far are public. Let's make this one an internal event. That means you
can also make the types used for the arguments internal as well.
You'll start by creating the new EventArgs derived class for reporting the new directory and progress.
Again, you can follow the recommendations to make an immutable reference type for the event arguments.
Next, define the event. This time, you'll use a different syntax. In addition to using the field syntax, you can explicitly
create the property, with add and remove handlers. In this sample, you won't need extra code in those handlers, but
this shows how you would create them.
In many ways, the code you write here mirrors the code the compiler generates for the field event definitions
you've seen earlier. You create the event using syntax very similar to that used for properties. Notice that the
handlers have different names: add and remove . These are called to subscribe to the event, or unsubscribe from
the event. Notice that you also must declare a private backing field to store the event variable. It is initialized to null.
Next, let's add the overload of the Search method that traverses subdirectories and raises both events. The easiest
way to accomplish this is to use a default argument to specify that you want to search all directories:
public void Search(string directory, string searchPattern, bool searchSubDirs = false)
{
if (searchSubDirs)
{
var allDirectories = Directory.GetDirectories(directory, "*.*", SearchOption.AllDirectories);
var completedDirs = 0;
var totalDirs = allDirectories.Length + 1;
foreach (var dir in allDirectories)
{
directoryChanged?.Invoke(this,
new SearchDirectoryArgs(dir, totalDirs, completedDirs++));
// Search 'dir' and its subdirectories for files that match the search pattern:
SearchDirectory(dir, searchPattern);
}
// Include the Current Directory:
directoryChanged?.Invoke(this,
new SearchDirectoryArgs(directory, totalDirs, completedDirs++));
SearchDirectory(directory, searchPattern);
}
else
{
SearchDirectory(directory, searchPattern);
}
}
At this point, you can run the application calling the overload for searching all sub-directories. There are no
subscribers on the new ChangeDirectory event, but using the ?.Invoke() idiom ensures that this works correctly.
Let's add a handler to write a line that shows the progress in the console window.
You've seen patterns that are followed throughout the .NET ecosystem. By learning these patterns and conventions,
you'll be writing idiomatic C# and .NET quickly.
Next, you'll see some changes in these patterns in the most recent release of .NET.
Next
The Updated .NET Core Event Pattern
3/12/2020 • 3 minutes to read • Edit Online
Previous
The previous article discussed the most common event patterns. .NET Core has a more relaxed pattern. In this
version, the EventHandler<TEventArgs> definition no longer has the constraint that TEventArgs must be a class
derived from System.EventArgs .
This increases flexibility for you, and is backwards compatible. Let's start with the flexibility. The class
System.EventArgs introduces one method: MemberwiseClone() , which creates a shallow copy of the object. That
method must use reflection in order to implement its functionality for any class derived from EventArgs . That
functionality is easier to create in a specific derived class. That effectively means that deriving from
System.EventArgs is a constraint that limits your designs, but does not provide any additional benefit. In fact, you
can change the definitions of FileFoundArgs and SearchDirectoryArgs so that they do not derive from EventArgs .
The program will work exactly the same.
You could also change the SearchDirectoryArgs to a struct, if you make one more change:
The additional change is to call the parameterless constructor before entering the constructor that initializes all the
fields. Without that addition, the rules of C# would report that the properties are being accessed before they have
been assigned.
You should not change the FileFoundArgs from a class (reference type) to a struct (value type). That's because the
protocol for handling cancel requires that the event arguments are passed by reference. If you made the same
change, the file search class could never observe any changes made by any of the event subscribers. A new copy of
the structure would be used for each subscriber, and that copy would be a different copy than the one seen by the
file search object.
Next, let's consider how this change can be backwards compatible. The removal of the constraint does not affect
any existing code. Any existing event argument types do still derive from System.EventArgs . Backwards
compatibility is one major reason why they will continue to derive from System.EventArgs . Any existing event
subscribers will be subscribers to an event that followed the classic pattern.
Following similar logic, any event argument type created now would not have any subscribers in any existing
codebases. New event types that do not derive from System.EventArgs will not break those codebases.
You need to reconcile this opposing guidance. Somehow, you must create a safe async void method. The basics of
the pattern you need to implement are below:
First, notice that the handler is marked as an async handler. Because it is being assigned to an event handler
delegate type, it will have a void return type. That means you must follow the pattern shown in the handler, and not
allow any exceptions to be thrown out of the context of the async handler. Because it does not return a task, there
is no task that can report the error by entering the faulted state. Because the method is async, the method can't
simply throw the exception. (The calling method has continued execution because it is async .) The actual runtime
behavior will be defined differently for different environments. It may terminate the thread or the process that
owns the thread, or leave the process in an indeterminate state. All of these potential outcomes are highly
undesirable.
That's why you should wrap the await statement for the async Task in your own try block. If it does cause a faulted
task, you can log the error. If it is an error from which your application cannot recover, you can exit the program
quickly and gracefully
Those are the major updates to the .NET event pattern. You will see many examples of the earlier versions in the
libraries you work with. However, you should understand what the latest patterns are as well.
The next article in this series helps you distinguish between using delegates and events in your designs. They
are similar concepts, and that article will help you make the best decision for your programs.
Next
Distinguishing Delegates and Events
9/3/2020 • 3 minutes to read • Edit Online
Previous
Developers that are new to the .NET Core platform often struggle when deciding between a design based on
delegates and a design based on events . The choice of delegates or events is often difficult, because the two
language features are similar. Events are even built using the language support for delegates.
They both offer a late binding scenario: they enable scenarios where a component communicates by calling a
method that is only known at runtime. They both support single and multiple subscriber methods. You may find
this referred to as singlecast and multicast support. They both support similar syntax for adding and removing
handlers. Finally, raising an event and calling a delegate use exactly the same method call syntax. They even both
support the same Invoke() method syntax for use with the ?. operator.
With all those similarities, it is easy to have trouble determining when to use which.
Evaluate Carefully
The above considerations are not hard and fast rules. Instead, they represent guidance that can help you decide
which choice is best for your particular usage. Because they are similar, you can even prototype both, and consider
which would be more natural to work with. They both handle late binding scenarios well. Use the one that
communicates your design the best.
Language Integrated Query (LINQ)
6/4/2019 • 3 minutes to read • Edit Online
Language-Integrated Query (LINQ) is the name for a set of technologies based on the integration of query
capabilities directly into the C# language. Traditionally, queries against data are expressed as simple strings
without type checking at compile time or IntelliSense support. Furthermore, you have to learn a different
query language for each type of data source: SQL databases, XML documents, various Web services, and so
on. With LINQ, a query is a first-class language construct, just like classes, methods, events.
For a developer who writes queries, the most visible "language-integrated" part of LINQ is the query
expression. Query expressions are written in a declarative query syntax. By using query syntax, you can
perform filtering, ordering, and grouping operations on data sources with a minimum of code. You use the
same basic query expression patterns to query and transform data in SQL databases, ADO .NET Datasets,
XML documents and streams, and .NET collections.
The following example shows the complete query operation. The complete operation includes creating a
data source, defining the query expression, and executing the query in a foreach statement.
class LINQQueryExpressions
{
static void Main()
{
Next steps
To learn more details about LINQ, start by becoming familiar with some basic concepts in Query expression
basics, and then read the documentation for the LINQ technology in which you are interested:
XML documents: LINQ to XML
ADO.NET Entity Framework: LINQ to entities
.NET collections, files, strings and so on: LINQ to objects
To gain a deeper understanding of LINQ in general, see LINQ in C#.
To start working with LINQ in C#, see the tutorial Working with LINQ.
Query expression basics
3/12/2020 • 12 minutes to read • Edit Online
This article introduces the basic concepts related to query expressions in C#.
IEnumerable<int> highScoresQuery =
from score in scores
where score > 80
orderby score descending
select score;
Retrieve a sequence of elements as in the previous example but transform them to a new type of object. For
example, a query may retrieve only the last names from certain customer records in a data source. Or it
may retrieve the complete record and then use it to construct another in-memory object type or even XML
data before generating the final result sequence. The following example shows a projection from an int to
a string . Note the new type of highScoresQuery .
IEnumerable<string> highScoresQuery2 =
from score in scores
where score > 80
orderby score descending
select $"The score is {score}";
In the previous example, note the use of parentheses around the query expression before the call to
the Count method. You can also express this by using a new variable to store the concrete result.
This technique is more readable because it keeps the variable that stores the query separate from the
query that stores a result.
IEnumerable<int> highScoresQuery3 =
from score in scores
where score > 80
select score;
In the previous example, the query is executed in the call to Count , because Count must iterate over the results in
order to determine the number of elements returned by highScoresQuery .
Query variable
In LINQ, a query variable is any variable that stores a query instead of the results of a query. More specifically, a
query variable is always an enumerable type that will produce a sequence of elements when it is iterated over in a
foreach statement or a direct call to its IEnumerator.MoveNext method.
The following code example shows a simple query expression with one data source, one filtering clause, one
ordering clause, and no transformation of the source elements. The select clause ends the query.
static void Main()
{
// Data source.
int[] scores = { 90, 71, 82, 93, 75, 82 };
// Query Expression.
IEnumerable<int> scoreQuery = //query variable
from score in scores //required
where score > 80 // optional
orderby score descending // optional
select score; //must end with select or group
In the previous example, scoreQuery is a query variable, which is sometimes referred to as just a query. The query
variable stores no actual result data, which is produced in the foreach loop. And when the foreach statement
executes, the query results are not returned through the query variable scoreQuery . Rather, they are returned
through the iteration variable testScore . The scoreQuery variable can be iterated in a second foreach loop. It will
produce the same results as long as neither it nor the data source has been modified.
A query variable may store a query that is expressed in query syntax or method syntax, or a combination of the
two. In the following examples, both queryMajorCities and queryMajorCities2 are query variables:
//Query syntax
IEnumerable<City> queryMajorCities =
from city in cities
where city.Population > 100000
select city;
// Method-based syntax
IEnumerable<City> queryMajorCities2 = cities.Where(c => c.Population > 100000);
On the other hand, the following two examples show variables that are not query variables even though each is
initialized with a query. They are not query variables because they store results:
int highestScore =
(from score in scores
select score)
.Max();
List<City> largeCitiesList =
(from country in countries
from city in country.Cities
where city.Population > 10000
select city)
.ToList();
For more information about the different ways to express queries, see Query syntax and method syntax in LINQ.
Explicit and implicit typing of query variables
This documentation usually provides the explicit type of the query variable in order to show the type relationship
between the query variable and the select clause. However, you can also use the var keyword to instruct the
compiler to infer the type of a query variable (or any other local variable) at compile time. For example, the query
example that was shown previously in this topic can also be expressed by using implicit typing:
For more information, see Implicitly typed local variables and Type relationships in LINQ query operations.
Starting a query expression
A query expression must begin with a from clause. It specifies a data source together with a range variable. The
range variable represents each successive element in the source sequence as the source sequence is being
traversed. The range variable is strongly typed based on the type of elements in the data source. In the following
example, because countries is an array of Country objects, the range variable is also typed as Country . Because
the range variable is strongly typed, you can use the dot operator to access any available members of the type.
IEnumerable<Country> countryAreaQuery =
from country in countries
where country.Area > 500000 //sq km
select country;
The range variable is in scope until the query is exited either with a semicolon or with a continuation clause.
A query expression may contain multiple from clauses. Use additional from clauses when each element in the
source sequence is itself a collection or contains a collection. For example, assume that you have a collection of
Country objects, each of which contains a collection of City objects named Cities . To query the City objects in
each Country , use two from clauses as shown here:
IEnumerable<City> cityQuery =
from country in countries
from city in country.Cities
where city.Population > 10000
select city;
var queryCountryGroups =
from country in countries
group country by country.Name[0];
IEnumerable<Country> sortedQuery =
from country in countries
orderby country.Area
select country;
The select clause can be used to transform source data into sequences of new types. This transformation is also
named a projection. In the following example, the select clause projects a sequence of anonymous types which
contains only a subset of the fields in the original element. Note that the new objects are initialized by using an
object initializer.
For more information about all the ways that a select clause can be used to transform source data, see select
clause.
Continuations with "into"
You can use the into keyword in a select or group clause to create a temporary identifier that stores a query.
Do this when you must perform additional query operations on a query after a grouping or select operation. In the
following example countries are grouped according to population in ranges of 10 million. After these groups are
created, additional clauses filter out some groups, and then to sort the groups in ascending order. To perform those
additional operations, the continuation represented by countryGroup is required.
IEnumerable<City> queryCityPop =
from city in cities
where city.Population < 200000 && city.Population > 100000
select city;
IEnumerable<Country> querySortedCountries =
from country in countries
orderby country.Area, country.Population descending
select country;
The ascending keyword is optional; it is the default sort order if no order is specified. For more information, see
orderby clause.
join clause
Use the join clause to associate and/or combine elements from one data source with elements from another
data source based on an equality comparison between specified keys in each element. In LINQ, join operations are
performed on sequences of objects whose elements are different types. After you have joined two sequences, you
must use a select or group statement to specify which element to store in the output sequence. You can also use
an anonymous type to combine properties from each set of associated elements into a new type for the output
sequence. The following example associates prod objects whose Category property matches one of the
categories in the categories string array. Products whose Category does not match any string in categories are
filtered out. The select statement projects a new type whose properties are taken from both cat and prod .
var categoryQuery =
from cat in categories
join prod in products on cat equals prod.Category
select new { Category = cat, Name = prod.Name };
You can also perform a group join by storing the results of the join operation into a temporary variable by using
the into keyword. For more information, see join clause.
let clause
Use the let clause to store the result of an expression, such as a method call, in a new range variable. In the
following example, the range variable firstName stores the first element of the array of strings that is returned by
Split .
string[] names = { "Svetlana Omelchenko", "Claire O'Donnell", "Sven Mortensen", "Cesar Garcia" };
IEnumerable<string> queryFirstNames =
from name in names
let firstName = name.Split(' ')[0]
select firstName;
var queryGroupMax =
from student in students
group student by student.GradeLevel into studentGroup
select new
{
Level = studentGroup.Key,
HighestScore =
(from student2 in studentGroup
select student2.Scores.Average())
.Max()
};
See also
C# programming guide
Language Integrated Query (LINQ)
Query keywords (LINQ)
Standard query operators overview
LINQ in C#
11/1/2019 • 2 minutes to read • Edit Online
This section contains links to topics that provide more detailed information about LINQ.
In this section
Introduction to LINQ queries
Describes the three parts of the basic LINQ query operation that are common across all languages and data
sources.
LINQ and generic types
Provides a brief introduction to generic types as they are used in LINQ.
Data transformations with LINQ
Describes the various ways that you can transform data retrieved in queries.
Type relationships in LINQ query operations
Describes how types are preserved and/or transformed in the three parts of a LINQ query operation
Query syntax and method syntax in LINQ
Compares method syntax and query syntax as two ways to express a LINQ query.
C# features that support LINQ
Describes the language constructs in C# that support LINQ.
Related sections
LINQ query expressions
Includes an overview of queries in LINQ and provides links to additional resources.
Standard query operators overview
Introduces the standard methods used in LINQ.
Write LINQ queries in C#
9/3/2020 • 4 minutes to read • Edit Online
This article shows the three ways in which you can write a LINQ query in C#:
1. Use query syntax.
2. Use method syntax.
3. Use a combination of query syntax and method syntax.
The following examples demonstrate some simple LINQ queries by using each approach listed previously. In
general, the rule is to use (1) whenever possible, and use (2) and (3) whenever necessary.
NOTE
These queries operate on simple in-memory collections; however, the basic syntax is identical to that used in LINQ to Entities
and LINQ to XML.
// Query #1.
List<int> numbers = new List<int>() { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
// Query #2.
IEnumerable<int> orderingQuery =
from num in numbers
where num < 3 || num > 7
orderby num ascending
select num;
// Query #3.
string[] groupingQuery = { "carrots", "cabbage", "broccoli", "beans", "barley" };
IEnumerable<IGrouping<char, string>> queryFoodGroups =
from item in groupingQuery
group item by item[0];
Note that the type of the queries is IEnumerable<T>. All of these queries could be written using var as shown in
the following example:
var query = from num in numbers...
In each previous example, the queries do not actually execute until you iterate over the query variable in a foreach
statement or other statement. For more information, see Introduction to LINQ Queries.
// Query #5.
IEnumerable<int> concatenationQuery = numbers1.Concat(numbers2);
If the method has Action or Func parameters, these are provided in the form of a lambda expression, as shown in
the following example:
// Query #6.
IEnumerable<int> largeNumbersQuery = numbers2.Where(c => c > 15);
In the previous queries, only Query #4 executes immediately. This is because it returns a single value, and not a
generic IEnumerable<T> collection. The method itself has to use foreach in order to compute its value.
Each of the previous queries can be written by using implicit typing with var, as shown in the following example:
Because Query #7 returns a single value and not a collection, the query executes immediately.
The previous query can be written by using implicit typing with var , as follows:
See also
Walkthrough: Writing Queries in C#
Language Integrated Query (LINQ)
where clause
Query a collection of objects
1/23/2019 • 2 minutes to read • Edit Online
This example shows how to perform a simple query over a list of Student objects. Each Student object contains
some basic information about the student, and a list that represents the student's scores on four examinations.
This application serves as the framework for many other examples in this section that use the same students data
source.
Example
The following query returns the students who received a score of 90 or greater on their first exam.
This query is intentionally simple to enable you to experiment. For example, you can try more conditions in the
where clause, or use an orderby clause to sort the results.
See also
Language Integrated Query (LINQ)
String interpolation
How to return a query from a method (C#
Programming Guide)
11/12/2019 • 2 minutes to read • Edit Online
This example shows how to return a query from a method as the return value and as an out parameter.
Query objects are composable, meaning that you can return a query from a method. Objects that represent queries
do not store the resulting collection, but rather the steps to produce the results when needed. The advantage of
returning query objects from methods is that they can be further composed or modified. Therefore any return
value or out parameter of a method that returns a query must also have that type. If a method materializes a
query into a concrete List<T> or Array type, it is considered to be returning the query results instead of the query
itself. A query variable that is returned from a method can still be composed or modified.
Example
In the following example, the first method returns a query as a return value, and the second method returns a
query as an out parameter. Note that in both cases it is a query that is returned, not query results.
class MQ
{
// QueryMethhod1 returns a query as its value.
IEnumerable<string> QueryMethod1(ref int[] ints)
{
var intsToStrings = from i in ints
where i > 4
select i.ToString();
return intsToStrings;
}
int[] nums = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
IEnumerable<string> myQuery2;
// QueryMethod2 returns a query as the value of its out parameter.
app.QueryMethod2(ref nums, out myQuery2);
See also
Language Integrated Query (LINQ)
Store the results of a query in memory
5/15/2019 • 2 minutes to read • Edit Online
A query is basically a set of instructions for how to retrieve and organize data. Queries are executed lazily, as each
subsequent item in the result is requested. When you use foreach to iterate the results, items are returned as
accessed. To evaluate a query and store its results without executing a foreach loop, just call one of the following
methods on the query variable:
ToList
ToArray
ToDictionary
ToLookup
We recommend that when you store the query results, you assign the returned collection object to a new variable
as shown in the following example:
Example
class StoreQueryResults
{
static List<int> numbers = new List<int>() { 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 };
static void Main()
{
IEnumerable<int> queryFactorsOfFour =
from num in numbers
where num % 4 == 0
select num;
See also
Language Integrated Query (LINQ)
Group query results
1/24/2019 • 8 minutes to read • Edit Online
Grouping is one of the most powerful capabilities of LINQ. The following examples show how to group data in
various ways:
By a single property.
By the first letter of a string property.
By a computed numeric range.
By Boolean predicate or other expression.
By a compound key.
In addition, the last two queries project their results into a new anonymous type that contains only the student's
first and last name. For more information, see the group clause.
Example
All the examples in this topic use the following helper classes and data sources.
Example
The following example shows how to group source elements by using a single property of the element as the
group key. In this case the key is a string , the student's last name. It is also possible to use a substring for the key.
The grouping operation uses the default equality comparer for the type.
Paste the following method into the StudentClass class. Change the calling statement in the Main method to
sc.GroupBySingleProperty() .
public void GroupBySingleProperty()
{
Console.WriteLine("Group by a single property in an object:");
Example
The following example shows how to group source elements by using something other than a property of the
object for the group key. In this example, the key is the first letter of the student's last name.
Paste the following method into the StudentClass class. Change the calling statement in the Main method to
sc.GroupBySubstring() .
public void GroupBySubstring()
{
Console.WriteLine("\r\nGroup by something other than a property of the object:");
var queryFirstLetters =
from student in students
group student by student.LastName[0];
Example
The following example shows how to group source elements by using a numeric range as a group key. The query
then projects the results into an anonymous type that contains only the first and last name and the percentile range
to which the student belongs. An anonymous type is used because it is not necessary to use the complete Student
object to display the results. GetPercentile is a helper function that calculates a percentile based on the student's
average score. The method returns an integer between 0 and 10.
Paste the following method into the StudentClass class. Change the calling statement in the Main method to
sc.GroupByRange() .
public void GroupByRange()
{
Console.WriteLine("\r\nGroup by numeric range and project into a new anonymous type:");
var queryNumericRange =
from student in students
let percentile = GetPercentile(student)
group new { student.FirstName, student.LastName } by percentile into percentGroup
orderby percentGroup.Key
select percentGroup;
Example
The following example shows how to group source elements by using a Boolean comparison expression. In this
example, the Boolean expression tests whether a student's average exam score is greater than 75. As in previous
examples, the results are projected into an anonymous type because the complete source element is not needed.
Note that the properties in the anonymous type become properties on the Key member and can be accessed by
name when the query is executed.
Paste the following method into the StudentClass class. Change the calling statement in the Main method to
sc.GroupByBoolean() .
public void GroupByBoolean()
{
Console.WriteLine("\r\nGroup by a Boolean into two groups with string keys");
Console.WriteLine("\"True\" and \"False\" and project into a new anonymous type:");
var queryGroupByAverages = from student in students
group new { student.FirstName, student.LastName }
by student.ExamScores.Average() > 75 into studentGroup
select studentGroup;
Example
The following example shows how to use an anonymous type to encapsulate a key that contains multiple values. In
this example, the first key value is the first letter of the student's last name. The second key value is a Boolean that
specifies whether the student scored over 85 on the first exam. You can order the groups by any property in the
key.
Paste the following method into the StudentClass class. Change the calling statement in the Main method to
sc.GroupByCompositeKey() .
public void GroupByCompositeKey()
{
var queryHighScoreGroups =
from student in students
group student by new { FirstLetter = student.LastName[0],
Score = student.ExamScores[0] > 85 } into studentGroup
orderby studentGroup.Key.FirstLetter
select studentGroup;
/* Output:
Group and order by a compound key:
Name starts with A who scored more than 85
Terry Adams
Name starts with F who scored more than 85
Fadi Fakhouri
Hanying Feng
Name starts with G who scored more than 85
Cesar Garcia
Hugo Garcia
Name starts with G who scored less than 85
Debra Garcia
Name starts with M who scored more than 85
Sven Mortensen
Name starts with O who scored less than 85
Claire O'Donnell
Name starts with O who scored more than 85
Svetlana Omelchenko
Name starts with T who scored less than 85
Lance Tucker
Name starts with T who scored more than 85
Michael Tucker
Name starts with Z who scored more than 85
Eugene Zabokritski
*/
See also
GroupBy
IGrouping<TKey,TElement>
Language Integrated Query (LINQ)
group clause
Anonymous Types
Perform a Subquery on a Grouping Operation
Create a Nested Group
Grouping Data
Create a nested group
1/24/2019 • 2 minutes to read • Edit Online
The following example shows how to create nested groups in a LINQ query expression. Each group that is created
according to student year or grade level is then further subdivided into groups based on the individuals' names.
Example
NOTE
This example contains references to objects that are defined in the sample code in Query a collection of objects.
public void QueryNestedGroups()
{
var queryNestedGroups =
from student in students
group student by student.Year into newGroup1
from newGroup2 in
(from student in newGroup1
group student by student.LastName)
group newGroup2 by newGroup1.Key;
Note that three nested foreach loops are required to iterate over the inner elements of a nested group.
See also
Language Integrated Query (LINQ)
Perform a subquery on a grouping operation
3/12/2020 • 2 minutes to read • Edit Online
This article shows two different ways to create a query that orders the source data into groups, and then performs
a subquery over each group individually. The basic technique in each example is to group the source elements by
using a continuation named newGroup , and then generating a new subquery against newGroup . This subquery is
run against each new group that is created by the outer query. Note that in this particular example the final output
is not a group, but a flat sequence of anonymous types.
For more information about how to group, see group clause.
For more information about continuations, see into. The following example uses an in-memory data structure as
the data source, but the same principles apply for any kind of LINQ data source.
Example
NOTE
This example contains references to objects that are defined in the sample code in Query a collection of objects.
The query in the snippet above can also be written using method syntax. The following code snippet has a
semantically equivalent query written using method syntax.
public void QueryMaxUsingMethodSyntax()
{
var queryGroupMax = students
.GroupBy(student => student.Year)
.Select(studentGroup => new
{
Level = studentGroup.Key,
HighestScore = studentGroup.Select(student2 => student2.ExamScores.Average()).Max()
});
See also
Language Integrated Query (LINQ)
Group results by contiguous keys
8/24/2018 • 7 minutes to read • Edit Online
The following example shows how to group elements into chunks that represent subsequences of contiguous keys.
For example, assume that you are given the following sequence of key-value pairs:
K EY VA L UE
A We
A think
A that
B Linq
C is
A really
B cool
B !
Thread-safety is accomplished by making a copy of each group or chunk as the source sequence is iterated, as
explained in the source code comments. If the source sequence has a large sequence of contiguous items, the
common language runtime may throw an OutOfMemoryException.
Example
The following example shows both the extension method and the client code that uses it:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ChunkIt
{
{
// Static class to contain the extension methods.
public static class MyExtensions
{
public static IEnumerable<IGrouping<TKey, TSource>> ChunkBy<TSource, TKey>(this IEnumerable<TSource>
source, Func<TSource, TKey> keySelector)
{
return source.ChunkBy(keySelector, EqualityComparer<TKey>.Default);
}
// Make a new Chunk (group) object that initially has one GroupItem, which is a copy of the
current source element.
current = new Chunk<TKey, TSource>(key, enumerator, value => comparer.Equals(key,
keySelector(value)));
// Return the Chunk. A Chunk is an IGrouping<TKey,TSource>, which is the return value of the
ChunkBy method.
// At this point the Chunk only has the first element in its source sequence. The remaining
elements will be
// returned only when the client code foreach's over this chunk. See Chunk.GetEnumerator for
more info.
yield return current;
// Check to see whether (a) the chunk has made a copy of all its source elements or
// (b) the iterator has reached the end of the source sequence. If the caller uses an inner
// foreach loop to iterate the chunk items, and that loop ran to completion,
// then the Chunk.GetEnumerator method will already have made
// copies of all chunk items before we get here. If the Chunk.GetEnumerator loop did not
// enumerate all elements in the chunk, we need to do it here to avoid corrupting the iterator
// for clients that may be calling us on a separate thread.
if (current.CopyAllChunkElements() == noMoreSourceElements)
{
yield break;
}
}
}
// A Chunk is a contiguous group of one or more source elements that have the same key. A Chunk
// has a key and a list of ChunkItem objects, which are copies of the elements in the source sequence.
class Chunk<TKey, TSource> : IGrouping<TKey, TSource>
{
// INVARIANT: DoneCopyingChunk == true ||
// (predicate != null && predicate(enumerator.Current) && current.Value == enumerator.Current)
// A Chunk has a linked list of ChunkItems, which represent the elements in the current chunk. Each
ChunkItem
// has a reference to the next ChunkItem in the list.
// has a reference to the next ChunkItem in the list.
class ChunkItem
{
public ChunkItem(TSource value)
{
Value = value;
}
public readonly TSource Value;
public ChunkItem Next = null;
}
// Flag to indicate the source iterator has reached the end of the source sequence.
internal bool isLastSourceElement = false;
// The end and beginning are the same until the list contains > 1 elements.
tail = head;
// Indicates that all chunk elements have been copied to the list of ChunkItems,
// and the source enumerator is either at the end, or else on an element with a new key.
// the tail of the linked list is set to null in the CopyNextChunkElement method if the
// key of the next element does not match the current chunk's key, or there are no more elements in
the source.
private bool DoneCopyingChunk => tail == null;
// If we are (a) at the end of the source, or (b) at the end of the current chunk
// then null out the enumerator and predicate for reuse with the next chunk.
if (isLastSourceElement || !predicate(enumerator.Current))
{
enumerator = null;
predicate = null;
}
else
{
tail.Next = new ChunkItem(enumerator.Current);
}
// Called after the end of the last chunk was reached. It first checks whether
// there are more elements in the source sequence. If there are, it
// Returns true if enumerator for this chunk was exhausted.
internal bool CopyAllChunkElements()
{
while (true)
{
lock (m_Lock)
{
if (DoneCopyingChunk)
{
// If isLastSourceElement is false,
// it signals to the outer iterator
// to continue iterating.
return isLastSourceElement;
}
else
{
CopyNextChunkElement();
}
}
}
}
// Invoked by the inner foreach loop. This method stays just one step ahead
// of the client requests. It adds the next element of the chunk only after
// the clients requests the last element in the list so far.
public IEnumerator<TSource> GetEnumerator()
{
//Specify the initial element to enumerate.
ChunkItem current = head;
// A simple named type is used for easier viewing in the debugger. Anonymous types
// work just as well with the ChunkBy operator.
public class KeyValPair
{
public string Key { get; set; }
public string Value { get; set; }
}
class Program
{
// The source sequence.
public static IEnumerable<KeyValPair> list;
To use the extension method in your project, copy the MyExtensions static class to a new or existing source code file
and if it is required, add a using directive for the namespace where it is located.
See also
Language Integrated Query (LINQ)
Dynamically specify predicate filters at runtime
1/24/2019 • 2 minutes to read • Edit Online
In some cases, you don't know until run time how many predicates you have to apply to source elements in the
where clause. One way to dynamically specify multiple predicate filters is to use the Contains method, as shown in
the following example. The example is constructed in two ways. First, the project is run by filtering on values that
are provided in the program. Then the project is run again by using input provided at run time.
5. Add the following line to the Main method in class DynamicPredicates , under the declaration of ids .
QueryById(ids);
default:
break;
}
Console.WriteLine($"The following students are at level {year}");
foreach (Student name in studentQuery)
{
Console.WriteLine($"{name.LastName}: {name.ID}");
}
}
3. In the Main method, replace the call to QueryByID with the following call, which sends the first element
from the args array as its argument: QueryByYear(args[0]) .
4. Run the project with a command line argument of an integer value between 1 and 4.
See also
Language Integrated Query (LINQ)
where clause
Perform inner joins
1/24/2019 • 10 minutes to read • Edit Online
In relational database terms, an inner join produces a result set in which each element of the first collection
appears one time for every matching element in the second collection. If an element in the first collection has no
matching elements, it does not appear in the result set. The Join method, which is called by the join clause in C#,
implements an inner join.
This article shows you how to perform four variations of an inner join:
A simple inner join that correlates elements from two data sources based on a simple key.
An inner join that correlates elements from two data sources based on a composite key. A composite key,
which is a key that consists of more than one value, enables you to correlate elements based on more than
one property.
A multiple join in which successive join operations are appended to each other.
An inner join that is implemented by using a group join.
class Pet
{
public string Name { get; set; }
public Person Owner { get; set; }
}
/// <summary>
/// Simple inner join.
/// </summary>
public static void InnerJoinExample()
{
Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };
Person rui = new Person { FirstName = "Rui", LastName = "Raposo" };
Note that the Person object whose LastName is "Huff" does not appear in the result set because there is no Pet
object that has Pet.Owner equal to that Person .
class Employee
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int EmployeeID { get; set; }
}
class Student
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int StudentID { get; set; }
}
/// <summary>
/// Performs a join operation using a composite key.
/// </summary>
public static void CompositeKeyJoinExample()
{
// Create a list of employees.
List<Employee> employees = new List<Employee> {
new Employee { FirstName = "Terry", LastName = "Adams", EmployeeID = 522459 },
new Employee { FirstName = "Charlotte", LastName = "Weiss", EmployeeID = 204467 },
new Employee { FirstName = "Magnus", LastName = "Hedland", EmployeeID = 866200 },
new Employee { FirstName = "Vernette", LastName = "Price", EmployeeID = 437139 } };
// Join the two data sources based on a composite key consisting of first and last name,
// to determine which employees are also students.
IEnumerable<string> query = from employee in employees
join student in students
on new { employee.FirstName, employee.LastName }
equals new { student.FirstName, student.LastName }
select employee.FirstName + " " + employee.LastName;
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
class Pet
{
public string Name { get; set; }
public Person Owner { get; set; }
}
Dog fourwheeldrive = new Dog { Name = "Four Wheel Drive", Owner = phyllis };
Dog duke = new Dog { Name = "Duke", Owner = magnus };
Dog denim = new Dog { Name = "Denim", Owner = terry };
Dog wiley = new Dog { Name = "Wiley", Owner = charlotte };
Dog snoopy = new Dog { Name = "Snoopy", Owner = rui };
Dog snickers = new Dog { Name = "Snickers", Owner = arlene };
// The first join matches Person and Cat.Owner from the list of people and
// cats, based on a common Person. The second join matches dogs whose names start
// with the same letter as the cats that have the same owner.
var query = from person in people
join cat in cats on person equals cat.Owner
join dog in dogs on
new { Owner = person, Letter = cat.Name.Substring(0, 1) }
equals new { dog.Owner, Letter = dog.Name.Substring(0, 1) }
select new { CatName = cat.Name, DogName = dog.Name };
foreach (var obj in query)
{
Console.WriteLine(
$"The cat \"{obj.CatName}\" shares a house, and the first letter of their name, with \"
{obj.DogName}\".");
}
}
By adding a second from clause to the query, this sequence of sequences is combined (or flattened) into one
longer sequence. The type of the elements of the final sequence is specified by the select clause. In this example,
that type is an anonymous type that consists of the Person.FirstName and Pet.Name properties for each matching
pair.
The result of query1 is equivalent to the result set that would have been obtained by using the join clause
without the into clause to perform an inner join. The query2 variable demonstrates this equivalent query.
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
class Pet
{
public string Name { get; set; }
public Person Owner { get; set; }
}
/// <summary>
/// Performs an inner join by using GroupJoin().
/// </summary>
public static void InnerGroupJoinExample()
{
Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };
See also
Join
GroupJoin
Perform grouped joins
Perform left outer joins
Anonymous types
Perform grouped joins
4/24/2020 • 5 minutes to read • Edit Online
The group join is useful for producing hierarchical data structures. It pairs each element from the first collection
with a set of correlated elements from the second collection.
For example, a class or a relational database table named Student might contain two fields: Id and Name . A
second class or relational database table named Course might contain two fields: StudentId and CourseTitle . A
group join of these two data sources, based on matching Student.Id and Course.StudentId , would group each
Student with a collection of Course objects (which might be empty).
NOTE
Each element of the first collection appears in the result set of a group join regardless of whether correlated elements are
found in the second collection. In the case where no correlated elements are found, the sequence of correlated elements for
that element is empty. The result selector therefore has access to every element of the first collection. This differs from the
result selector in a non-group join, which cannot access elements from the first collection that have no match in the second
collection.
WARNING
Enumerable.GroupJoin has no direct equivalent in traditional relational database terms. However, this method does
implement a superset of inner joins and left outer joins. Both of these operations can be written in terms of a grouped join.
For more information, see Join Operations and Entity Framework Core, GroupJoin.
The first example in this article shows you how to perform a group join. The second example shows you how to
use a group join to create XML elements.
class Pet
{
public string Name { get; set; }
public Person Owner { get; set; }
}
/// <summary>
/// This example performs a grouped join.
/// </summary>
public static void GroupJoinExample()
{
Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
class Pet
{
public string Name { get; set; }
public Person Owner { get; set; }
}
/// <summary>
/// This example creates XML output from a grouped join.
/// </summary>
public static void GroupJoinXMLExample()
{
Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };
// Create XML to display the hierarchical organization of people and their pets.
XElement ownersAndPets = new XElement("PetOwners",
from person in people
join pet in pets on person equals pet.Owner into gj
select new XElement("Person",
new XAttribute("FirstName", person.FirstName),
new XAttribute("LastName", person.LastName),
from subpet in gj
select new XElement("Pet", subpet.Name)));
Console.WriteLine(ownersAndPets);
}
See also
Join
GroupJoin
Perform inner joins
Perform left outer joins
Anonymous types
Perform left outer joins
1/24/2019 • 2 minutes to read • Edit Online
A left outer join is a join in which each element of the first collection is returned, regardless of whether it has any
correlated elements in the second collection. You can use LINQ to perform a left outer join by calling the
DefaultIfEmpty method on the results of a group join.
Example
The following example demonstrates how to use the DefaultIfEmpty method on the results of a group join to
perform a left outer join.
The first step in producing a left outer join of two collections is to perform an inner join by using a group join. (See
Perform inner joins for an explanation of this process.) In this example, the list of Person objects is inner-joined to
the list of Pet objects based on a Person object that matches Pet.Owner .
The second step is to include each element of the first (left) collection in the result set even if that element has no
matches in the right collection. This is accomplished by calling DefaultIfEmpty on each sequence of matching
elements from the group join. In this example, DefaultIfEmpty is called on each sequence of matching Pet objects.
The method returns a collection that contains a single, default value if the sequence of matching Pet objects is
empty for any Person object, thereby ensuring that each Person object is represented in the result collection.
NOTE
The default value for a reference type is null ; therefore, the example checks for a null reference before accessing each
element of each Pet collection.
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
class Pet
{
public string Name { get; set; }
public Person Owner { get; set; }
}
See also
Join
GroupJoin
Perform inner joins
Perform grouped joins
Anonymous types
Order the results of a join clause
1/24/2019 • 2 minutes to read • Edit Online
This example shows how to order the results of a join operation. Note that the ordering is performed after the join.
Although you can use an orderby clause with one or more of the source sequences before the join, generally we
do not recommend it. Some LINQ providers might not preserve that ordering after the join.
Example
This query creates a group join, and then sorts the groups based on the category element, which is still in scope.
Inside the anonymous type initializer, a sub-query orders all the matching elements from the products sequence.
class HowToOrderJoins
{
#region Data
class Product
{
public string Name { get; set; }
public int CategoryID { get; set; }
}
class Category
{
public string Name { get; set; }
public int ID { get; set; }
}
void OrderJoin1()
void OrderJoin1()
{
var groupJoinQuery2 =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
orderby category.Name
select new
{
Category = category.Name,
Products = from prod2 in prodGroup
orderby prod2.Name
select prod2
};
See also
Language Integrated Query (LINQ)
orderby clause
join clause
Join by using composite keys
1/24/2019 • 2 minutes to read • Edit Online
This example shows how to perform join operations in which you want to use more than one key to define a
match. This is accomplished by using a composite key. You create a composite key as an anonymous type or
named typed with the values that you want to compare. If the query variable will be passed across method
boundaries, use a named type that overrides Equals and GetHashCode for the key. The names of the properties,
and the order in which they occur, must be identical in each key.
Example
The following example demonstrates how to use a composite key to join data from three tables:
Type inference on composite keys depends on the names of the properties in the keys, and the order in which they
occur. If the properties in the source sequences don't have the same names, you must assign new names in the
keys. For example, if the Orders table and OrderDetails table each used different names for their columns, you
could create composite keys by assigning identical names in the anonymous types:
See also
Language Integrated Query (LINQ)
join clause
group clause
Perform custom join operations
1/24/2019 • 5 minutes to read • Edit Online
This example shows how to perform join operations that aren't possible with the join clause. In a query
expression, the join clause is limited to, and optimized for, equijoins, which are by far the most common type of
join operation. When performing an equijoin, you will probably always get the best performance by using the
join clause.
NOTE
Don't confuse this kind of custom join operation with the use of multiple from clauses to access inner collections. For more
information, see join clause.
Example
The first method in the following example shows a simple cross join. Cross joins must be used with caution
because they can produce very large result sets. However, they can be useful in some scenarios for creating source
sequences against which additional queries are run.
The second method produces a sequence of all the products whose category ID is listed in the category list on the
left side. Note the use of the let clause and the Contains method to create a temporary array. It also is possible
to create the array before the query and eliminate the first from clause.
class CustomJoins
{
#region Data
class Product
{
public string Name { get; set; }
public int CategoryID { get; set; }
}
class Category
{
public string Name { get; set; }
public int ID { get; set; }
}
void CrossJoin()
{
var crossJoinQuery =
from c in categories
from p in products
select new { c.ID, p.Name };
void NonEquijoin()
{
var nonEquijoinQuery =
from p in products
let catIds = from c in categories
select c.ID
where catIds.Contains(p.CategoryID) == true
select new { Product = p.Name, CategoryID = p.CategoryID };
Console.WriteLine("Non-equijoin query:");
foreach (var v in nonEquijoinQuery)
{
Console.WriteLine($"{v.CategoryID,-5}{v.Product}");
}
}
}
/* Output:
Cross Join Query:
1 Tea
1 Mustard
1 Pickles
1 Carrots
1 Bok Choy
1 Peaches
1 Peaches
1 Melons
1 Ice Cream
1 Mackerel
2 Tea
2 Mustard
2 Pickles
2 Carrots
2 Bok Choy
2 Peaches
2 Melons
2 Ice Cream
2 Mackerel
3 Tea
3 Mustard
3 Pickles
3 Carrots
3 Bok Choy
3 Peaches
3 Melons
3 Ice Cream
3 Mackerel
Non-equijoin query:
1 Tea
2 Mustard
2 Pickles
3 Carrots
3 Bok Choy
Press any key to exit.
*/
Example
In the following example, the query must join two sequences based on matching keys that, in the case of the inner
(right side) sequence, cannot be obtained prior to the join clause itself. If this join were performed with a join
clause, then the Split method would have to be called for each element. The use of multiple from clauses
enables the query to avoid the overhead of the repeated method call. However, since join is optimized, in this
particular case it might still be faster than using multiple from clauses. The results will vary depending primarily
on how expensive the method call is.
class MergeTwoCSVFiles
{
static void Main()
{
// See section Compiling the Code for information about the data files.
string[] names = System.IO.File.ReadAllLines(@"../../../names.csv");
string[] scores = System.IO.File.ReadAllLines(@"../../../scores.csv");
class Student
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int ID { get; set; }
public List<int> ExamScores { get; set; }
}
/* Output:
The average score of Omelchenko Svetlana is 82.5.
The average score of O'Donnell Claire is 72.25.
The average score of Mortensen Sven is 84.5.
The average score of Garcia Cesar is 88.25.
The average score of Garcia Debra is 67.
The average score of Fakhouri Fadi is 92.25.
The average score of Feng Hanying is 88.
The average score of Garcia Hugo is 85.75.
The average score of Tucker Lance is 81.75.
The average score of Adams Terry is 85.25.
The average score of Zabokritski Eugene is 83.
The average score of Tucker Michael is 92.
*/
See also
Language Integrated Query (LINQ)
join clause
Order the results of a join clause
Handle null values in query expressions
3/25/2020 • 2 minutes to read • Edit Online
This example shows how to handle possible null values in source collections. An object collection such as an
IEnumerable<T> can contain elements whose value is null. If a source collection is null or contains an element
whose value is null, and your query does not handle null values, a NullReferenceException will be thrown when you
execute the query.
Example
You can code defensively to avoid a null reference exception as shown in the following example:
var query1 =
from c in categories
where c != null
join p in products on c.ID equals
p?.CategoryID
select new { Category = c.Name, Name = p.Name };
In the previous example, the where clause filters out all null elements in the categories sequence. This technique is
independent of the null check in the join clause. The conditional expression with null in this example works because
Products.CategoryID is of type int? which is shorthand for Nullable<int> .
Example
In a join clause, if only one of the comparison keys is a nullable value type, you can cast the other to a nullable value
type in the query expression. In the following example, assume that EmployeeID is a column that contains values of
type int? :
See also
Nullable<T>
Language Integrated Query (LINQ)
Nullable value types
Handle exceptions in query expressions
1/24/2019 • 2 minutes to read • Edit Online
It's possible to call any method in the context of a query expression. However, we recommend that you avoid
calling any method in a query expression that can create a side effect such as modifying the contents of the data
source or throwing an exception. This example shows how to avoid raising exceptions when you call methods in a
query expression without violating the general .NET guidelines on exception handling. Those guidelines state that
it's acceptable to catch a specific exception when you understand why it's thrown in a given context. For more
information, see Best Practices for Exceptions.
The final example shows how to handle those cases when you must throw an exception during execution of a
query.
Example
The following example shows how to move exception handling code outside a query expression. This is only
possible when the method does not depend on any variables local to the query.
class ExceptionsOutsideQuery
{
static void Main()
{
// DO THIS with a datasource that might
// throw an exception. It is easier to deal with
// outside of the query expression.
IEnumerable<int> dataSource;
try
{
dataSource = GetData();
}
catch (InvalidOperationException)
{
// Handle (or don't handle) the exception
// in the way that is appropriate for your application.
Console.WriteLine("Invalid operation");
goto Exit;
}
class QueryThatThrows
{
static void Main()
{
// Data source.
string[] files = { "fileA.txt", "fileB.txt", "fileC.txt" };
See also
Language Integrated Query (LINQ)
Asynchronous programming
9/3/2020 • 10 minutes to read • Edit Online
If you have any I/O-bound needs (such as requesting data from a network, accessing a database, or reading and
writing to a file system), you'll want to utilize asynchronous programming. You could also have CPU-bound code,
such as performing an expensive calculation, which is also a good scenario for writing async code.
C# has a language-level asynchronous programming model, which allows for easily writing asynchronous code,
without having to juggle callbacks or conform to a library that supports asynchrony. It follows what is known as
the Task-based Asynchronous Pattern (TAP).
The code expresses the intent (downloading data asynchronously) without getting bogged down in interacting
with Task objects.
CPU -bound example: Perform a calculation for a game
Say you're writing a mobile game where pressing a button can inflict damage on many enemies on the screen.
Performing the damage calculation can be expensive, and doing it on the UI thread would make the game appear
to pause as the calculation is performed!
The best way to handle this is to start a background thread, which does the work using Task.Run , and await its
result using await . This allows the UI to feel smooth as the work is being done.
private DamageResult CalculateDamageDone()
{
// Code omitted:
//
// Does an expensive calculation and returns
// the result of that calculation.
}
This code cleanly expresses the intent of the button's click event, it doesn't require managing a background thread
manually, and it does so in a non-blocking way.
What happens under the covers
There are many moving pieces where asynchronous operations are concerned. If you're curious about what's
happening underneath the covers of Task and Task<T> , see the Async in-depth article for more information.
On the C# side of things, the compiler transforms your code into a state machine that keeps track of things like
yielding execution when an await is reached and resuming execution when a background job has finished.
For the theoretically-inclined, this is an implementation of the Promise Model of asynchrony.
More examples
The following examples demonstrate various ways you can write async code in C#. They cover a few different
scenarios you may come across.
Extract data from a network
This snippet downloads the HTML from the homepage at https://dotnetfoundation.org and counts the number of
times the string ".NET" occurs in the HTML. It uses ASP.NET to define a Web API controller method, which performs
this task and returns the number.
NOTE
If you plan on doing HTML parsing in production code, don't use regular expressions. Use a parsing library instead.
[HttpGet, Route("DotNetCount")]
public async Task<int> GetDotNetCount()
{
// Suspends GetDotNetCount() to allow the caller (the web server)
// to accept another request, rather than blocking on this one.
var html = await _httpClient.GetStringAsync("https://dotnetfoundation.org");
Here's the same scenario written for a Universal Windows App, which performs the same task when a Button is
pressed:
// Any other work on the UI thread can be done here, such as enabling a Progress Bar.
// This is important to do here, before the "await" call, so that the user
// sees the progress bar before execution of this method is yielded.
NetworkProgressBar.IsEnabled = true;
NetworkProgressBar.Visibility = Visibility.Visible;
NetworkProgressBar.IsEnabled = false;
NetworkProgressBar.Visibility = Visibility.Collapsed;
}
Wait for multiple tasks to complete
You may find yourself in a situation where you need to retrieve multiple pieces of data concurrently. The Task API
contains two methods, Task.WhenAll and Task.WhenAny, that allow you to write asynchronous code that performs
a non-blocking wait on multiple background jobs.
This example shows how you might grab User data for a set of userId s.
Although it's less code, use caution when mixing LINQ with asynchronous code. Because LINQ uses deferred (lazy)
execution, async calls won't happen immediately as they do in a foreach loop unless you force the generated
sequence to iterate with a call to .ToList() or .ToArray() .
async void is the only way to allow asynchronous event handlers to work because events do not have return
types (thus cannot make use of Task and Task<T> ). Any other use of async void does not follow the TAP model
and can be challenging to use, such as:
Exceptions thrown in an async void method can't be caught outside of that method.
async void methods are difficult to test.
async void methods can cause bad side effects if the caller isn't expecting them to be async.
Tread carefully when using async lambdas in LINQ expressions
Lambda expressions in LINQ use deferred execution, meaning code could end up executing at a time when you're
not expecting it to. The introduction of blocking tasks into this can easily result in a deadlock if not written
correctly. Additionally, the nesting of asynchronous code like this can also make it more difficult to reason about
the execution of the code. Async and LINQ are powerful, but should be used together as carefully and clearly as
possible.
Write code that awaits Tasks in a non-blocking manner
Blocking the current thread as a means to wait for a Task to complete can result in deadlocks and blocked
context threads, and can require more complex error-handling. The following table provides guidance on how to
deal with waiting for tasks in a non-blocking way:
Returning a Task object from async methods can introduce performance bottlenecks in certain paths. Task is a
reference type, so using it means allocating an object. In cases where a method declared with the async modifier
returns a cached result or completes synchronously, the extra allocations can become a significant time cost in
performance critical sections of code. It can become costly if those allocations occur in tight loops. For more
information, see generalized async return types.
Consider using ConfigureAwait(false)
A common question is, "when should I use the Task.ConfigureAwait(Boolean) method?". The method allows for a
Task instance to configure its awaiter. This is an important consideration and setting it incorrectly could
potentially have performance implications and even deadlocks. For more information on ConfigureAwait , see the
ConfigureAwait FAQ.
Write less stateful code
Don't depend on the state of global objects or the execution of certain methods. Instead, depend only on the
return values of methods. Why?
Code will be easier to reason about.
Code will be easier to test.
Mixing async and synchronous code is far simpler.
Race conditions can typically be avoided altogether.
Depending on return values makes coordinating async code simple.
(Bonus) it works really well with dependency injection.
A recommended goal is to achieve complete or near-complete Referential Transparency in your code. Doing so
will result in an extremely predictable, testable, and maintainable codebase.
Other resources
Async in-depth provides more information about how Tasks work.
Asynchronous programming with async and await (C#)
Lucian Wischik's Six Essential Tips for Async are a wonderful resource for async programming
Pattern Matching
9/3/2020 • 13 minutes to read • Edit Online
Patterns test that a value has a certain shape, and can extract information from the value when it has the matching
shape. Pattern matching provides more concise syntax for algorithms you already use today. You already create
pattern matching algorithms using existing syntax. You write if or switch statements that test values. Then,
when those statements match, you extract and use information from that value. The new syntax elements are
extensions to statements you're already familiar with: is and switch . These new extensions combine testing a
value and extracting that information.
In this article, we'll look at the new syntax to show you how it enables readable, concise code. Pattern matching
enables idioms where data and the code are separated, unlike object-oriented designs where data and the
methods that manipulate them are tightly coupled.
To illustrate these new idioms, let's work with structures that represent geometric shapes using pattern matching
statements. You're probably familiar with building class hierarchies and creating virtual methods and overridden
methods to customize object behavior based on the runtime type of the object.
Those techniques aren't possible for data that isn't structured in a class hierarchy. When data and methods are
separate, you need other tools. The new pattern matching constructs enable cleaner syntax to examine data and
manipulate control flow based on any condition of that data. You already write if statements and switch that
test a variable's value. You write is statements that test a variable's type. Pattern matching adds new capabilities
to those statements.
In this article, you'll build a method that computes the area of different geometric shapes. But, you'll do it without
resorting to object-oriented techniques and building a class hierarchy for the different shapes. You'll use pattern
matching instead. As you go through this sample, contrast this code with how it would be structured as an object
hierarchy. When the data you must query and manipulate isn't a class hierarchy, pattern matching enables elegant
designs.
Rather than starting with an abstract shape definition and adding different specific shape classes, let's start
instead with simple data only definitions for each of the geometric shapes:
public class Square
{
public double Side { get; }
From these structures, let's write a method that computes the area of some shape.
That code above is a classic expression of the type pattern: You're testing a variable to determine its type and
taking a different action based on that type.
This code becomes simpler using extensions to the is expression to assign a variable if the test succeeds:
In this updated version, the is expression both tests the variable and assigns it to a new variable of the proper
type. Also, notice that this version includes the Rectangle type, which is a struct . The new is expression works
with value types as well as reference types.
Language rules for pattern matching expressions help you avoid misusing the results of a match expression. In
the example above, the variables s , c , and r are only in scope and definitely assigned when the respective
pattern match expressions have true results. If you try to use either variable in another location, your code
generates compiler errors.
Let's examine both of those rules in detail, beginning with scope. The variable c is in scope only in the else
branch of the first if statement. The variable s is in scope in the method ComputeAreaModernIs . That's because
each branch of an if statement establishes a separate scope for variables. However, the if statement itself
doesn't. That means variables declared in the if statement are in the same scope as the if statement (the
method in this case). This behavior isn't specific to pattern matching, but is the defined behavior for variable
scopes and if and else statements.
The variables c and s are assigned when the respective if statements are true because of the definitely
assigned when true mechanism.
TIP
The samples in this topic use the recommended construct where a pattern match is expression definitely assigns the
match variable in the true branch of the if statement. You could reverse the logic by saying
if (!(shape is Square s)) and the variable s would be definitely assigned only in the false branch. While this is
valid C#, it is not recommended because it is more confusing to follow the logic.
These rules mean that you're unlikely to accidentally access the result of a pattern match expression when that
pattern wasn't met.
The only pattern supported by the switch statement was the constant pattern. It was further limited to numeric
types and the string type. Those restrictions have been removed, and you can now write a switch statement
using the type pattern:
The pattern matching switch statement uses familiar syntax to developers who have used the traditional C-style
switch statement. Each case is evaluated and the code beneath the condition that matches the input variable is
executed. Code execution can't "fall through" from one case expression to the next; the syntax of the case
statement requires that each case end with a break , return , or goto .
NOTE
The goto statements to jump to another label are valid only for the constant pattern (the classic switch statement).
There are important new rules governing the switch statement. The restrictions on the type of the variable in the
switch expression have been removed. Any type, such as object in this example, may be used. The case
expressions are no longer limited to constant values. Removing that limitation means that reordering switch
sections may change a program's behavior.
When limited to constant values, no more than one case label could match the value of the switch expression.
Combine that with the rule that every switch section must not fall through to the next section, and it followed
that the switch sections could be rearranged in any order without affecting behavior. Now, with more
generalized switch expressions, the order of each section matters. The switch expressions are evaluated in
textual order. Execution transfers to the first switch label that matches the switch expression.
The default case will only be executed if no other case labels match. The default case is evaluated last,
regardless of its textual order. If there's no default case, and none of the other case statements match, execution
continues at the statement following the switch statement. None of the case labels code is executed.
case Square s:
return s.Side * s.Side;
case Circle c:
return c.Radius * c.Radius * Math.PI;
default:
throw new ArgumentException(
message: "shape is not a recognized shape",
paramName: nameof(shape));
}
}
This change demonstrates a few important points about the new syntax. First, multiple case labels can be applied
to one switch section. The statement block is executed when any of those labels is true . In this instance, if the
switch expression is either a circle or a square with 0 area, the method returns the constant 0.
This example introduces two different variables in the two case labels for the first switch block. Notice that the
statements in this switch block don't use either the variables c (for the circle) or s (for the square). Neither of
those variables is definitely assigned in this switch block. If either of these cases match, clearly one of the
variables has been assigned. However, it's impossible to tell which has been assigned at compile time, because
either case could match at runtime. For that reason, most times when you use multiple case labels for the same
block, you won't introduce a new variable in the case statement, or you'll only use the variable in the when
clause.
Having added those shapes with 0 area, let's add a couple more shape types: a rectangle and a triangle:
case Square s:
return s.Side * s.Side;
case Circle c:
return c.Radius * c.Radius * Math.PI;
case Triangle t:
return t.Base * t.Height / 2;
case Rectangle r:
return r.Length * r.Height;
default:
throw new ArgumentException(
message: "shape is not a recognized shape",
paramName: nameof(shape));
}
}
This set of changes adds case labels for the degenerate case, and labels and blocks for each of the new shapes.
Finally, you can add a null case to ensure the argument isn't null :
case Square s:
return s.Side * s.Side;
case Circle c:
return c.Radius * c.Radius * Math.PI;
case Triangle t:
return t.Base * t.Height / 2;
case Rectangle r:
return r.Length * r.Height;
case null:
throw new ArgumentNullException(paramName: nameof(shape), message: "Shape must not be null");
default:
throw new ArgumentException(
message: "shape is not a recognized shape",
paramName: nameof(shape));
}
}
The special behavior for the null pattern is interesting because the constant null in the pattern doesn't have a
type but can be converted to any reference type or nullable value type. Rather than convert a null to any type,
the language defines that a null value won't match any type pattern, regardless of the compile-time type of the
variable. This behavior makes the new switch based type pattern consistent with the is statement: is
statements always return false when the value being checked is null . It's also simpler: once you've checked the
type, you don't need an additional null check. You can see that from the fact that there are no null checks in any of
the case blocks of the samples above: they aren't necessary, since matching the type pattern guarantees a non-
null value.
NOTE
The compiler does not emit a warning in those cases where a default case has been written but will never execute. This is
consistent with current switch statement behavior where all possible cases have been listed.
The third rule introduces uses where a var case may be useful. Imagine that you're doing a pattern match where
the input is a string and you're searching for known command values. You might write something like:
case "square":
return new Square(4);
case "large-circle":
return new Circle(12);
The var case matches null , the empty string, or any string that contains only white space. Notice that the
preceding code uses the ?. operator to ensure that it doesn't accidentally throw a NullReferenceException. The
default case handles any other string values that aren't understood by this command parser.
This is one example where you may want to consider a var case expression that is distinct from a default
expression.
Conclusions
Pattern Matching constructs enable you to easily manage control flow among different variables and types that
aren't related by an inheritance hierarchy. You can also control logic to use any condition you test on the variable.
It enables patterns and idioms that you'll need more often as you build more distributed applications, where data
and the methods that manipulate that data are separate. You'll notice that the shape structs used in this sample
don't contain any methods, just read-only properties. Pattern Matching works with any data type. You write
expressions that examine the object, and make control flow decisions based on those conditions.
Compare the code from this sample with the design that would follow from creating a class hierarchy for an
abstract Shape and specific derived shapes each with their own implementation of a virtual method to calculate
the area. You'll often find that pattern matching expressions can be a very useful tool when you're working with
data and want to separate the data storage concerns from the behavior concerns.
See also
Tutorial: Using pattern matching features to extend data types
Write safe and efficient C# code
4/21/2020 • 16 minutes to read • Edit Online
New features in C# enable you to write verifiable safe code with better performance. If you carefully apply these
techniques, fewer scenarios require unsafe code. These features make it easier to use references to value types as
method arguments and method returns. When done safely, these techniques minimize copying value types. By
using value types, you can minimize the number of allocations and garbage collection passes.
Much of the sample code in this article uses features added in C# 7.2. To use those features, you must configure
your project to use C# 7.2 or later. For more information on setting the language version, see configure the
language version.
This article focuses on techniques for efficient resource management. One advantage to using value types is that
they often avoid heap allocations. The disadvantage is that they're copied by value. This trade-off makes it harder
to optimize algorithms that operate on large amounts of data. New language features in C# 7.2 provide
mechanisms that enable safe efficient code using references to value types. Use these features wisely to minimize
both allocations and copy operations. This article explores those new features.
This article focuses on the following resource management techniques:
Declare a readonly struct to express that a type is immutable . That enables the compiler to save defensive
copies when using in parameters.
If a type can't be immutable, declare struct members readonly to indicate that the member doesn't modify
state.
Use a ref readonly return when the return value is a struct larger than IntPtr.Size and the storage lifetime is
greater than the method returning the value.
When the size of a readonly struct is bigger than IntPtr.Size, you should pass it as an in parameter for
performance reasons.
Never pass a struct as an in parameter unless it's declared with the readonly modifier or the method calls
only readonly members of the struct. Violating this guidance may negatively affect performance and could
lead to an obscure behavior.
Use a ref struct , or a readonly ref struct such as Span<T> or ReadOnlySpan<T> to work with memory as
a sequence of bytes.
These techniques force you to balance two competing goals with regard to references and values . Variables that
are reference types hold a reference to the location in memory. Variables that are value types directly contain their
value. These differences highlight the key differences that are important for managing memory resources. Value
types are typically copied when passed to a method or returned from a method. This behavior includes copying
the value of this when calling members of a value type. The cost of the copy is related to the size of the type.
Reference types are allocated on the managed heap. Each new object requires a new allocation, and
subsequently must be reclaimed. Both these operations take time. The reference is copied when a reference type is
passed as an argument to a method or returned from a method.
This article uses the following example concept of the 3D-point structure to explain these recommendations:
public struct Point3D
{
public double X;
public double Y;
public double Z;
}
Follow this recommendation whenever your design intent is to create an immutable value type. Any performance
improvements are an added benefit. The readonly struct clearly expresses your design intent.
The preceding sample shows many of the locations where you can apply the readonly modifier: methods,
properties, and property accessors. If you use auto-implemented properties, the compiler adds the readonly
modifier to the get accessor for read-write properties. The compiler adds the readonly modifier to the auto-
implemented property declarations for properties with only a get accessor.
Adding the readonly modifier to members that don't mutate state provides two related benefits. First, the
compiler enforces your intent. That member can't mutate the struct's state. Second, the compiler won't create
defensive copies of in parameters when accessing a readonly member. The compiler can make this optimization
safely because it guarantees that the struct is not modified by a readonly member.
Use ref readonly return statements for large structures when possible
You can return values by reference when the value being returned isn't local to the returning method. Returning by
reference means that only the reference is copied, not the structure. In the following example, the Origin property
can't use a ref return because the value being returned is a local variable:
However, the following property definition can be returned by reference because the returned value is a static
member:
public struct Point3D
{
private static Point3D origin = new Point3D(0,0,0);
You don't want callers modifying the origin, so you should return the value by ref readonly :
Returning ref readonly enables you to save copying larger structures and preserve the immutability of your
internal data members.
At the call site, callers make the choice to use the Origin property as a ref readonly or as a value:
The first assignment in the preceding code makes a copy of the Origin constant and assigns that copy. The
second assigns a reference. Notice that the readonly modifier must be part of the declaration of the variable. The
reference to which it refers can't be modified. Attempts to do so result in a compile-time error.
The readonly modifier is required on the declaration of originReference .
The compiler enforces that the caller can't modify the reference. Attempts to assign the value directly generate a
compile-time error. However, the compiler can't know if any member method modifies the state of the struct. To
ensure that the object isn't modified, the compiler creates a copy and calls member references using that copy. Any
modifications are to that defensive copy.
The arguments are two structures that each contain three doubles. A double is 8 bytes, so each argument is 24
bytes. By specifying the in modifier, you pass a 4 byte or 8-byte reference to those arguments, depending on the
architecture of the machine. The difference in size is small, but it adds up when your application calls this method
in a tight loop using many different values.
The in modifier complements out and ref in other ways as well. You can't create overloads of a method that
differ only in the presence of in , out , or ref . These new rules extend the same behavior that had always been
defined for out and ref parameters. Like the out and ref modifiers, value types aren't boxed because the in
modifier is applied.
The in modifier may be applied to any member that takes parameters: methods, delegates, lambdas, local
functions, indexers, operators.
Another feature of in parameters is that you may use literal values or constants for the argument to an in
parameter. Also, unlike a ref or out parameter, you don't need to apply the in modifier at the call site. The
following code shows you two examples of calling the CalculateDistance method. The first uses two local
variables passed by reference. The second includes a temporary variable created as part of the method call.
There are several ways in which the compiler enforces the read-only nature of an in argument. First of all, the
called method can't directly assign to an in parameter. It can't directly assign to any field of an in parameter
when that value is a struct type. In addition, you can't pass an in parameter to any method using the ref or
out modifier. These rules apply to any field of an in parameter, provided the field is a struct type and the
parameter is also a struct type. In fact, these rules apply for multiple layers of member access provided the types
at all levels of member access are structs . The compiler enforces that struct types passed as in arguments
and their struct members are read-only variables when used as arguments to other methods.
The use of in parameters can avoid the potential performance costs of making copies. It doesn't change the
semantics of any method call. Therefore, you don't need to specify the in modifier at the call site. Omitting the
in modifier at the call site informs the compiler that it's allowed to make a copy of the argument for the
following reasons:
There exists an implicit conversion but not an identity conversion from the argument type to the parameter
type.
The argument is an expression but doesn't have a known storage variable.
An overload exists that differs by the presence or absence of in . In that case, the by value overload is a better
match.
These rules are useful as you update existing code to use read-only reference arguments. Inside the called method,
you can call any instance method that uses by value parameters. In those instances, a copy of the in parameter is
created. Because the compiler may create a temporary variable for any in parameter, you can also specify default
values for any in parameter. The following code specifies the origin (point 0,0) as the default value for the second
point:
To force the compiler to pass read-only arguments by reference, specify the in modifier on the arguments at the
call site, as shown in the following code:
This behavior makes it easier to adopt in parameters over time in large codebases where performance gains are
possible. You add the in modifier to method signatures first. Then, you can add the in modifier at call sites and
create readonly struct types to enable the compiler to avoid creating defensive copies of in parameters in more
locations.
The in parameter designation can also be used with reference types or numeric values. However, the benefits in
both cases are minimal, if any.
The Point3D structure is not a readonly struct. There are six different property access calls in the body of this
method. On first examination, you may have thought these accesses were safe. After all, a get accessor shouldn't
modify the state of the object. But there's no language rule that enforces that. It's only a common convention. Any
type could implement a get accessor that modified the internal state. Without some language guarantee, the
compiler must create a temporary copy of the argument before calling any member not marked with the
readonly modifier. The temporary storage is created on the stack, the values of the argument are copied to the
temporary storage, and the value is copied to the stack for each member access as the this argument. In many
situations, these copies harm performance enough that pass-by-value is faster than pass-by-readonly-reference
when the argument type isn't a readonly struct and the method calls members that aren't marked readonly . If
you mark all methods that don't modify the struct state as readonly , the compiler can safely determine that the
struct state isn't modified, and a defensive copy is not needed.
Instead, if the distance calculation uses the immutable struct, ReadonlyPoint3D , temporary objects aren't needed:
The compiler generates more efficient code when you call members of a readonly struct : The this reference,
instead of a copy of the receiver, is always an in parameter passed by reference to the member method. This
optimization saves copying when you use a readonly struct as an in argument.
You shouldn't pass a nullable value type as an in argument. The Nullable<T> type isn't declared as a read-only
struct. That means the compiler must generate defensive copies for any nullable value type argument passed to a
method using the in modifier on the parameter declaration.
You can see an example program that demonstrates the performance differences using BenchmarkDotNet in our
samples repository on GitHub. It compares passing a mutable struct by value and by reference with passing an
immutable struct by value and by reference. The use of the immutable struct and pass by reference is fastest.
Use ref struct types to work with blocks or memory on a single stack
frame
A related language feature is the ability to declare a value type that must be constrained to a single stack frame.
This restriction enables the compiler to make several optimizations. The primary motivation for this feature was
Span<T> and related structures. You'll achieve performance improvements from these enhancements by using
new and updated .NET APIs that make use of the Span<T> type.
You may have similar requirements working with memory created using stackalloc or when using memory from
interop APIs. You can define your own ref struct types for those needs.
Conclusions
Using value types minimizes the number of allocation operations:
Storage for value types is stack allocated for local variables and method arguments.
Storage for value types that are members of other objects is allocated as part of that object, not as a separate
allocation.
Storage for value type return values is stack allocated.
Contrast that with reference types in those same situations:
Storage for reference types are heap allocated for local variables and method arguments. The reference is
stored on the stack.
Storage for reference types that are members of other objects are separately allocated on the heap. The
containing object stores the reference.
Storage for reference type return values is heap allocated. The reference to that storage is stored on the stack.
Minimizing allocations comes with tradeoffs. You copy more memory when the size of the struct is larger than
the size of a reference. A reference is typically 64 bits or 32 bits, and depends on the target machine CPU.
These tradeoffs generally have minimal performance impact. However, for large structs or larger collections, the
performance impact increases. The impact can be large in tight loops and hot paths for programs.
These enhancements to the C# language are designed for performance critical algorithms where minimizing
memory allocations is a major factor in achieving the necessary performance. You may find that you don't often
use these features in the code you write. However, these enhancements have been adopted throughout .NET. As
more and more APIs make use of these features, you'll see the performance of your applications improve.
See also
ref keyword
Ref returns and ref locals
Expression Trees
9/3/2020 • 2 minutes to read • Edit Online
If you have used LINQ, you have experience with a rich library where the Func types are part of the API set. (If you
are not familiar with LINQ, you probably want to read the LINQ tutorial and the article about lambda expressions
before this one.) Expression Trees provide richer interaction with the arguments that are functions.
You write function arguments, typically using Lambda Expressions, when you create LINQ queries. In a typical
LINQ query, those function arguments are transformed into a delegate the compiler creates.
When you want to have a richer interaction, you need to use Expression Trees. Expression Trees represent code as a
structure that you can examine, modify, or execute. These tools give you the power to manipulate code during run
time. You can write code that examines running algorithms, or injects new capabilities. In more advanced
scenarios, you can modify running algorithms, and even translate C# expressions into another form for execution
in another environment.
You've likely already written code that uses Expression Trees. Entity Framework's LINQ APIs accept Expression Trees
as the arguments for the LINQ Query Expression Pattern. That enables Entity Framework to translate the query
you wrote in C# into SQL that executes in the database engine. Another example is Moq, which is a popular
mocking framework for .NET.
The remaining sections of this tutorial will explore what Expression Trees are, examine the framework classes that
support expression trees, and show you how to work with expression trees. You'll learn how to read expression
trees, how to create expression trees, how to create modified expression trees, and how to execute the code
represented by expression trees. After reading, you will be ready to use these structures to create rich adaptive
algorithms.
1. Expression Trees Explained
Understand the structure and concepts behind Expression Trees.
2. Framework Types Supporting Expression Trees
Learn about the structures and classes that define and manipulate expression trees.
3. Executing Expressions
Learn how to convert an expression tree represented as a Lambda Expression into a delegate and execute
the resulting delegate.
4. Interpreting Expressions
Learn how to traverse and examine expression trees to understand what code the expression tree
represents.
5. Building Expressions
Learn how to construct the nodes for an expression tree and build expression trees.
6. Translating Expressions
Learn how to build a modified copy of an expression tree, or translate an expression tree into a different
format.
7. Summing up
Review the information on expression trees.
Expression Trees Explained
10/29/2019 • 4 minutes to read • Edit Online
Previous -- Overview
An Expression Tree is a data structure that defines code. They are based on the same structures that a compiler uses
to analyze code and generate the compiled output. As you read through this tutorial, you will notice quite a bit of
similarity between Expression Trees and the types used in the Roslyn APIs to build Analyzers and CodeFixes.
(Analyzers and CodeFixes are NuGet packages that perform static analysis on code and can suggest potential fixes
for a developer.) The concepts are similar, and the end result is a data structure that allows examination of the
source code in a meaningful way. However, Expression Trees are based on a totally different set of classes and APIs
than the Roslyn APIs.
Let's look at a simple example. Here's a line of code:
var sum = 1 + 2;
If you were to analyze this as an expression tree, the tree contains several nodes. The outermost node is a variable
declaration statement with assignment ( var sum = 1 + 2; ) That outermost node contains several child nodes: a
variable declaration, an assignment operator, and an expression representing the right hand side of the equals sign.
That expression is further subdivided into expressions that represent the addition operation, and left and right
operands of the addition.
Let's drill down a bit more into the expressions that make up the right side of the equals sign. The expression is
1 + 2 . That's a binary expression. More specifically, it's a binary addition expression. A binary addition expression
has two children, representing the left and right nodes of the addition expression. Here, both nodes are constant
expressions: The left operand is the value 1 , and the right operand is the value 2 .
Visually, the entire statement is a tree: You could start at the root node, and travel to each node in the tree to see
the code that makes up the statement:
Variable declaration statement with assignment ( var sum = 1 + 2; )
Implicit variable type declaration ( var sum )
Implicit var keyword ( var )
Variable name declaration ( sum )
Assignment operator ( = )
Binary addition expression ( 1 + 2 )
Left operand ( 1 )
Addition operator ( + )
Right operand ( 2 )
This may look complicated, but it is very powerful. Following the same process, you can decompose much more
complicated expressions. Consider this expression:
if (addFive.NodeType == ExpressionType.Lambda)
{
var lambdaExp = (LambdaExpression)addFive;
Console.WriteLine(parameter.Name);
Console.WriteLine(parameter.Type);
}
You can see from this simple example that many types are involved in creating and working with expression trees.
That complexity is necessary to provide the capabilities of the rich vocabulary provided by the C# language.
You'll find more as you look at each of those three areas. Invariably, you will find what you need when you start
with one of those three steps.
Next -- Executing Expression Trees
Executing Expression Trees
3/12/2020 • 6 minutes to read • Edit Online
Optionally, you can also provide a DebugInfoGenerator that will receive the symbol debugging information for the
generated delegate object. This enables you to convert the expression tree into a delegate object, and have full
debugging information about the generated delegate.
You would convert an expression into a delegate using the following code:
Notice that the delegate type is based on the expression type. You must know the return type and the argument list
if you want to use the delegate object in a strongly typed manner. The LambdaExpression.Compile() method returns
the Delegate type. You will have to cast it to the correct delegate type to have any compile-time tools check the
argument list or return type.
Caveats
Compiling a lambda expression to a delegate and invoking that delegate is one of the simplest operations you can
perform with an expression tree. However, even with this simple operation, there are caveats you must be aware of.
Lambda Expressions create closures over any local variables that are referenced in the expression. You must
guarantee that any variables that would be part of the delegate are usable at the location where you call Compile ,
and when you execute the resulting delegate.
In general, the compiler will ensure that this is true. However, if your expression accesses a variable that
implements IDisposable , it's possible that your code might dispose of the object while it is still held by the
expression tree.
For example, this code works fine, because int does not implement IDisposable :
The delegate has captured a reference to the local variable constant . That variable is accessed at any time later,
when the function returned by CreateBoundFunc executes.
However, consider this (rather contrived) class that implements IDisposable :
If you use it in an expression as shown below, you'll get an ObjectDisposedException when you execute the code
referenced by the Resource.Argument property:
The delegate returned from this method has closed over the constant object, which has been disposed of. (It's
been disposed, because it was declared in a using statement.)
Now, when you execute the delegate returned from this method, you'll have a ObjectDisposedException thrown at
the point of execution.
It does seem strange to have a runtime error representing a compile-time construct, but that's the world we enter
when we work with expression trees.
There are a lot of permutations of this problem, so it's hard to offer general guidance to avoid it. Be careful about
accessing local variables when defining expressions, and be careful about accessing state in the current object
(represented by this ) when creating an expression tree that can be returned by a public API.
The code in your expression may reference methods or properties in other assemblies. That assembly must be
accessible when the expression is defined, and when it is compiled, and when the resulting delegate is invoked.
You'll be met with a ReferencedAssemblyNotFoundException in cases where it is not present.
Summary
Expression Trees that represent lambda expressions can be compiled to create a delegate that you can execute. This
provides one mechanism to execute the code represented by an expression tree.
The Expression Tree does represent the code that would execute for any given construct you create. As long as the
environment where you compile and execute the code matches the environment where you create the expression,
everything works as expected. When that doesn't happen, the errors are very predictable, and they will be caught
in your first tests of any code using the expression trees.
Next -- Interpreting Expressions
Interpreting Expressions
9/3/2020 • 14 minutes to read • Edit Online
Now, let's write the code that would examine this expression and write out some important properties about it.
Here's that code:
I'm not using var to declare this expression tree, as it is not possible because the right-hand side of the
assignment is implicitly typed.
The root node is a LambdaExpression . In order to get the interesting code on the right-hand side of the =>
operator, you need to find one of the children of the LambdaExpression . We'll do that with all the expressions in this
section. The parent node does help us find the return type of the LambdaExpression .
To examine each node in this expression, we'll need to recursively visit a number of nodes. Here's a simple first
implementation:
Expression<Func<int, int, int>> addition = (a, b) => a + b;
You'll notice a lot of repetition in the code sample above. Let's clean that up and build a more general purpose
expression node visitor. That's going to require us to write a recursive algorithm. Any node could be of a type that
might have children. Any node that has children requires us to visit those children and determine what that node
is. Here's the cleaned up version that utilizes recursion to visit the addition operations:
// Lambda Visitor
public class LambdaVisitor : Visitor
{
private readonly LambdaExpression node;
public LambdaVisitor(LambdaExpression node) : base(node)
{
this.node = node;
}
// Parameter visitor:
public class ParameterVisitor : Visitor
{
private readonly ParameterExpression node;
public ParameterVisitor(ParameterExpression node) : base(node)
{
this.node = node;
}
// Constant visitor:
public class ConstantVisitor : Visitor
{
private readonly ConstantExpression node;
public ConstantVisitor(ConstantExpression node) : base(node)
{
this.node = node;
}
This algorithm is the basis of an algorithm that can visit any arbitrary LambdaExpression . There are many holes,
namely that the code I created only looks for a very small sample of the possible sets of expression tree nodes that
it may encounter. However, you can still learn quite a bit from what it produces. (The default case in the
Visitor.CreateFromExpression method prints a message to the error console when a new node type is
encountered. That way, you know to add a new expression type.)
When you run this visitor on the addition expression shown above, you get the following output:
Now that you've built a more general visitor implementation, you can visit and process many more different types
of expressions.
Before you run this on the visitor algorithm, try a thought exercise to work out what the output might be.
Remember that the + operator is a binary operator: it must have two children, representing the left and right
operands. There are several possible ways to construct a tree that could be correct:
Expression<Func<int>> sum1 = () => 1 + (2 + (3 + 4));
Expression<Func<int>> sum2 = () => ((1 + 2) + 3) + 4;
You can see the separation into two possible answers to highlight the most promising. The first represents right
associative expressions. The second represent left associative expressions. The advantage of both of those two
formats is that the format scales to any arbitrary number of addition expressions.
If you do run this expression through the visitor, you will see this output, verifying that the simple addition
expression is left associative.
In order to run this sample, and see the full expression tree, I had to make one change to the source expression
tree. When the expression tree contains all constants, the resulting tree simply contains the constant value of 10 .
The compiler performs all the addition and reduces the expression to its simplest form. Simply adding one variable
in the expression is sufficient to see the original tree:
Create a visitor for this sum and run the visitor you'll see this output:
You can also run any of the other samples through the visitor code and see what tree it represents. Here's an
example of the sum3 expression above (with an additional parameter to prevent the compiler from computing the
constant):
Notice that the parentheses are not part of the output. There are no nodes in the expression tree that represent the
parentheses in the input expression. The structure of the expression tree contains all the information necessary to
communicate the precedence.
This code represents one possible implementation for the mathematical factorial function. The way I've written this
code highlights two limitations of building expression trees by assigning lambda expressions to Expressions. First,
statement lambdas are not allowed. That means I can't use loops, blocks, if / else statements, and other control
structures common in C#. I'm limited to using expressions. Second, I can't recursively call the same expression. I
could if it were already a delegate, but I can't call it in its expression tree form. In the section on building expression
trees, you'll learn techniques to overcome these limitations.
In this expression, you'll encounter nodes of all these types:
1. Equal (binary expression)
2. Multiply (binary expression)
3. Conditional (the ? : expression)
4. Method Call Expression (calling Range() and Aggregate() )
One way to modify the visitor algorithm is to keep executing it, and write the node type every time you reach your
default clause. After a few iterations, you'll have seen each of the potential nodes. Then, you have all you need.
The result would be something like this:
Creating Nodes
Let's start relatively simply again. We'll use the addition expression I've been working with throughout these
sections:
To construct that expression tree, you must construct the leaf nodes. The leaf nodes are constants, so you can use
the Expression.Constant method to create the nodes:
Once you've got the addition expression, you can create the lambda expression:
This is a very simple lambda expression, because it contains no arguments. Later in this section, you'll see how to
map arguments to parameters and build more complicated expressions.
For expressions that are as simple as this one, you may combine all the calls into a single statement:
Creating the multiplication and addition expressions follows the pattern you've already seen:
Next, you need to create a method call expression for the call to Math.Sqrt .
And then finally, you put the method call into a lambda expression, and make sure to define the arguments to the
lambda expression:
In this more complicated example, you see a couple more techniques that you will often need to create expression
trees.
First, you need to create the objects that represent parameters or local variables before you use them. Once you've
created those objects, you can use them in your expression tree wherever you need.
Second, you need to use a subset of the Reflection APIs to create a MethodInfo object so that you can create an
expression tree to access that method. You must limit yourself to the subset of the Reflection APIs that are
available on the .NET Core platform. Again, these techniques will extend to other expression trees.
Notice above that I did not build the expression tree, but simply the delegate. Using the Expression class, you
can't build statement lambdas. Here's the code that is required to build the same functionality. It's complicated by
the fact that there isn't an API to build a while loop, instead you need to build a loop that contains a conditional
test, and a label target to break out of the loop.
The code to build the expression tree for the factorial function is quite a bit longer, more complicated, and it's
riddled with labels and break statements and other elements we'd like to avoid in our everyday coding tasks.
For this section, I've also updated the visitor code to visit every node in this expression tree and write out
information about the nodes that are created in this sample. You can view or download the sample code at the
dotnet/docs GitHub repository. Experiment for yourself by building and running the samples. For download
instructions, see Samples and Tutorials.
Translating is Visiting
The code you build to translate an expression tree is an extension of what you've already seen to visit all the nodes
in a tree. When you translate an expression tree, you visit all the nodes, and while visiting them, build the new tree.
The new tree may contain references to the original nodes, or new nodes that you have placed in the tree.
Let's see this in action by visiting an expression tree, and creating a new tree with some replacement nodes. In this
example, let's replace any constant with a constant that is ten times larger. Otherwise, we'll leave the expression
tree intact. Rather than reading the value of the constant, and replacing it with a new constant, we'll make this
replacement by replacing the constant node with a new node that performs the multiplication.
Here, once you find a constant node, you create a new multiplication node whose children are the original
constant, and the constant 10 :
By replacing the original node with the substitute, a new tree is formed that contains our modifications. We can
verify that by compiling and executing the replaced tree.
There's quite a bit of code here, but the concepts are very approachable. This code visits children in a depth first
search. When it encounters a constant node, the visitor returns the value of the constant. After the visitor has
visited both children, those children will have computed the sum computed for that subtree. The addition node can
now compute its sum. Once all the nodes in the expression tree have been visited, the sum will have been
computed. You can trace the execution by running the sample in the debugger and tracing the execution.
Let's make it easier to trace how the nodes are analyzed and how the sum is computed by traversing the tree.
Here's an updated version of the Aggregate method that includes quite a bit of tracing information:
private static int Aggregate(Expression exp)
{
if (exp.NodeType == ExpressionType.Constant)
{
var constantExp = (ConstantExpression)exp;
Console.Error.WriteLine($"Found Constant: {constantExp.Value}");
return (int)constantExp.Value;
}
else if (exp.NodeType == ExpressionType.Add)
{
var addExp = (BinaryExpression)exp;
Console.Error.WriteLine("Found Addition Expression");
Console.Error.WriteLine("Computing Left node");
var leftOperand = Aggregate(addExp.Left);
Console.Error.WriteLine($"Left is: {leftOperand}");
Console.Error.WriteLine("Computing Right node");
var rightOperand = Aggregate(addExp.Right);
Console.Error.WriteLine($"Right is: {rightOperand}");
var sum = leftOperand + rightOperand;
Console.Error.WriteLine($"Computed sum: {sum}");
return sum;
}
else throw new NotSupportedException("Haven't written this yet");
}
10
Found Addition Expression
Computing Left node
Found Addition Expression
Computing Left node
Found Constant: 1
Left is: 1
Computing Right node
Found Constant: 2
Right is: 2
Computed sum: 3
Left is: 3
Computing Right node
Found Addition Expression
Computing Left node
Found Constant: 3
Left is: 3
Computing Right node
Found Constant: 4
Right is: 4
Computed sum: 7
Right is: 7
Computed sum: 10
10
Trace the output and follow along in the code above. You should be able to work out how the code visits each node
and computes the sum as it goes through the tree and finds the sum.
Now, let's look at a different run, with the expression given by sum1 :
While the final answer is the same, the tree traversal is completely different. The nodes are traveled in a different
order, because the tree was constructed with different operations occurring first.
Learning More
This sample shows a small subset of the code you would build to traverse and interpret the algorithms
represented by an expression tree. For a complete discussion of all the work necessary to build a general purpose
library that translates expression trees into another language, please read this series by Matt Warren. It goes into
great detail on how to translate any of the code you might find in an expression tree.
I hope you've now seen the true power of expression trees. You can examine a set of code, make any changes you'd
like to that code, and execute the changed version. Because the expression trees are immutable, you can create
new trees by using the components of existing trees. This minimizes the amount of memory needed to create
modified expression trees.
Next -- Summing up
Expression Trees Summary
3/12/2020 • 2 minutes to read • Edit Online
Limitations
There are some newer C# language elements that don't translate well into expression trees. Expression trees
cannot contain await expressions, or async lambda expressions. Many of the features added in the C# 6 release
don't appear exactly as written in expression trees. Instead, newer features will be exposed in expressions trees in
the equivalent, earlier syntax. This may not be as much of a limitation as you might think. In fact, it means that your
code that interprets expression trees will likely still work the same when new language features are introduced.
Even with these limitations, expression trees do enable you to create dynamic algorithms that rely on interpreting
and modifying code that is represented as a data structure. It's a powerful tool, and it's one of the features of the
.NET ecosystem that enables rich libraries such as Entity Framework to accomplish what they do.
Interoperability (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
Interoperability enables you to preserve and take advantage of existing investments in unmanaged code. Code that
runs under the control of the common language runtime (CLR) is called managed code, and code that runs outside
the CLR is called unmanaged code. COM, COM+, C++ components, ActiveX components, and Microsoft Windows
API are examples of unmanaged code.
.NET enables interoperability with unmanaged code through platform invoke services, the
System.Runtime.InteropServices namespace, C++ interoperability, and COM interoperability (COM interop).
In This Section
Interoperability Overview
Describes methods to interoperate between C# managed code and unmanaged code.
How to access Office interop objects by using C# features
Describes features that are introduced in Visual C# to facilitate Office programming.
How to use indexed properties in COM interop programming
Describes how to use indexed properties to access COM properties that have parameters.
How to use platform invoke to play a WAV file
Describes how to use platform invoke services to play a .wav sound file on the Windows operating system.
Walkthrough: Office Programming
Shows how to create an Excel workbook and a Word document that contains a link to the workbook.
Example COM Class
Demonstrates how to expose a C# class as a COM object.
C# Language Specification
For more information, see Basic concepts in the C# Language Specification. The language specification is the
definitive source for C# syntax and usage.
See also
Marshal.ReleaseComObject
C# Programming Guide
Interoperating with Unmanaged Code
Walkthrough: Office Programming
Document your code with XML comments
3/12/2020 • 28 minutes to read • Edit Online
XML documentation comments are a special kind of comment, added above the definition of any user-defined type
or member. They are special because they can be processed by the compiler to generate an XML documentation file
at compile time. The compiler-generated XML file can be distributed alongside your .NET assembly so that Visual
Studio and other IDEs can use IntelliSense to show quick information about types or members. Additionally, the
XML file can be run through tools like DocFX and Sandcastle to generate API reference websites.
XML documentation comments, like all other comments, are ignored by the compiler.
You can generate the XML file at compile time by doing one of the following:
If you are developing an application with .NET Core from the command line, you can add a
GenerateDocumentationFile element to the <PropertyGroup> section of your .csproj project file. You can also
specify the path to the documentation file directly using DocumentationFile element. The following example
generates an XML file in the project directory with the same root filename as the assembly:
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
If you are developing an application using Visual Studio, right-click on the project and select Proper ties . In
the properties dialog, select the Build tab, and check XML documentation file . You can also change the
location to which the compiler writes the file.
If you are compiling a .NET Framework application from the command line, add the -doc compiler option
when compiling.
XML documentation comments use triple forward slashes ( /// ) and an XML formatted comment body. For
example:
/// <summary>
/// This class does something.
/// </summary>
public class SomeClass
{
}
Walkthrough
Let's walk through documenting a very basic math library to make it easy for new developers to
understand/contribute and for third-party developers to use.
Here's code for the simple math library:
/*
The main Math class
Contains all methods for performing basic math functions
*/
public class Math
{
// Adds two integers and returns the result
public static int Add(int a, int b)
{
// If any parameter is equal to the max value of an integer
// and the other is greater than zero
if ((a == int.MaxValue && b > 0) || (b == int.MaxValue && a > 0))
throw new System.OverflowException();
return a + b;
}
return a + b;
}
The sample library supports four major arithmetic operations ( add , subtract , multiply , and divide ) on int
and double data types.
Now you want to be able to create an API reference document from your code for third-party developers who use
your library but don't have access to the source code. As mentioned earlier XML documentation tags can be used to
achieve this. You will now be introduced to the standard XML tags the C# compiler supports.
<summary>
The <summary> tag adds brief information about a type or member. I'll demonstrate its use by adding it to the Math
class definition and the first Add method. Feel free to apply it to the rest of your code.
/*
The main Math class
Contains all methods for performing basic math functions
*/
/// <summary>
/// The main Math class.
/// Contains all methods for performing basic math functions.
/// </summary>
public class Math
{
// Adds two integers and returns the result
/// <summary>
/// Adds two integers and returns the result.
/// </summary>
public static int Add(int a, int b)
{
// If any parameter is equal to the max value of an integer
// and the other is greater than zero
if ((a == int.MaxValue && b > 0) || (b == int.MaxValue && a > 0))
throw new System.OverflowException();
return a + b;
}
}
The <summary> tag is important, and we recommend that you include it because its content is the primary source of
type or member information in IntelliSense or an API reference document.
<remarks>
The <remarks> tag supplements the information about types or members that the <summary> tag provides. In this
example, you'll just add it to the class.
/*
The main Math class
Contains all methods for performing basic math functions
*/
/// <summary>
/// The main Math class.
/// Contains all methods for performing basic math functions.
/// </summary>
/// <remarks>
/// This class can add, subtract, multiply and divide.
/// </remarks>
public class Math
{
}
<returns>
The <returns> tag describes the return value of a method declaration. As before, the following example illustrates
the <returns> tag on the first Add method. You can do the same on other methods.
return a + b;
}
<value>
The <value> tag is similar to the <returns> tag, except that you use it for properties. Assuming your Math library
had a static property called PI , here's how you'd use this tag:
/*
The main Math class
Contains all methods for performing basic math functions
*/
/// <summary>
/// The main Math class.
/// Contains all methods for performing basic math functions.
/// </summary>
/// <remarks>
/// This class can add, subtract, multiply and divide.
/// These operations can be performed on both integers and doubles
/// </remarks>
public class Math
{
/// <value>Gets the value of PI.</value>
public static double PI { get; }
}
<example>
You use the <example> tag to include an example in your XML documentation. This involves using the child <code>
tag.
// Adds two integers and returns the result
/// <summary>
/// Adds two integers and returns the result.
/// </summary>
/// <returns>
/// The sum of two integers.
/// </returns>
/// <example>
/// <code>
/// int c = Math.Add(4, 5);
/// if (c > 10)
/// {
/// Console.WriteLine(c);
/// }
/// </code>
/// </example>
public static int Add(int a, int b)
{
// If any parameter is equal to the max value of an integer
// and the other is greater than zero
if ((a == int.MaxValue && b > 0) || (b == int.MaxValue && a > 0))
throw new System.OverflowException();
return a + b;
}
The code tag preserves line breaks and indentation for longer examples.
<para>
You use the <para> tag to format the content within its parent tag. <para> is usually used inside a tag, such as
<remarks> or <returns> , to divide text into paragraphs. You can format the contents of the <remarks> tag for your
class definition.
/*
The main Math class
Contains all methods for performing basic math functions
*/
/// <summary>
/// The main Math class.
/// Contains all methods for performing basic math functions.
/// </summary>
/// <remarks>
/// <para>This class can add, subtract, multiply and divide.</para>
/// <para>These operations can be performed on both integers and doubles.</para>
/// </remarks>
public class Math
{
}
<c>
Still on the topic of formatting, you use the <c> tag for marking part of text as code. It's like the <code> tag but
inline. It's useful when you want to show a quick code example as part of a tag's content. Let's update the
documentation for the Math class.
/*
The main Math class
Contains all methods for performing basic math functions
*/
/// <summary>
/// The main <c>Math</c> class.
/// Contains all methods for performing basic math functions.
/// </summary>
public class Math
{
}
<exception>
By using the <exception> tag, you let your developers know that a method can throw specific exceptions. Looking
at your Math library, you can see that both Add methods throw an exception if a certain condition is met. Not so
obvious, though, is that integer Divide method throws as well if the b parameter is zero. Now add exception
documentation to this method.
/*
The main Math class
Contains all methods for performing basic math functions
*/
/// <summary>
/// The main <c>Math</c> class.
/// Contains all methods for performing basic math functions.
/// </summary>
public class Math
{
/// <summary>
/// Adds two integers and returns the result.
/// </summary>
/// <returns>
/// The sum of two integers.
/// </returns>
/// <example>
/// <code>
/// int c = Math.Add(4, 5);
/// if (c > 10)
/// {
/// Console.WriteLine(c);
/// }
/// </code>
/// </example>
/// <exception cref="System.OverflowException">Thrown when one parameter is max
/// and the other is greater than 0.</exception>
public static int Add(int a, int b)
{
if ((a == int.MaxValue && b > 0) || (b == int.MaxValue && a > 0))
throw new System.OverflowException();
return a + b;
}
/// <summary>
/// Adds two doubles and returns the result.
/// </summary>
/// <returns>
/// The sum of two doubles.
/// </returns>
/// <exception cref="System.OverflowException">Thrown when one parameter is max
/// and the other is greater than zero.</exception>
public static double Add(double a, double b)
{
{
if ((a == double.MaxValue && b > 0) || (b == double.MaxValue && a > 0))
throw new System.OverflowException();
return a + b;
}
/// <summary>
/// Divides an integer by another and returns the result.
/// </summary>
/// <returns>
/// The division of two integers.
/// </returns>
/// <exception cref="System.DivideByZeroException">Thrown when a division by zero occurs.</exception>
public static int Divide(int a, int b)
{
return a / b;
}
/// <summary>
/// Divides a double by another and returns the result.
/// </summary>
/// <returns>
/// The division of two doubles.
/// </returns>
/// <exception cref="System.DivideByZeroException">Thrown when a division by zero occurs.</exception>
public static double Divide(double a, double b)
{
return a / b;
}
}
The cref attribute represents a reference to an exception that is available from the current compilation
environment. This can be any type defined in the project or a referenced assembly. The compiler will issue a
warning if its value cannot be resolved.
<see>
The <see> tag lets you create a clickable link to a documentation page for another code element. In our next
example, we'll create a clickable link between the two Add methods.
/*
The main Math class
Contains all methods for performing basic math functions
*/
/// <summary>
/// The main <c>Math</c> class.
/// Contains all methods for performing basic math functions.
/// </summary>
public class Math
{
/// <summary>
/// Adds two integers and returns the result.
/// </summary>
/// <returns>
/// The sum of two integers.
/// </returns>
/// <example>
/// <code>
/// int c = Math.Add(4, 5);
/// if (c > 10)
/// {
/// Console.WriteLine(c);
/// }
/// </code>
/// </example>
/// <exception cref="System.OverflowException">Thrown when one parameter is max
/// and the other is greater than 0.</exception>
/// See <see cref="Math.Add(double, double)"/> to add doubles.
public static int Add(int a, int b)
{
if ((a == int.MaxValue && b > 0) || (b == int.MaxValue && a > 0))
throw new System.OverflowException();
return a + b;
}
/// <summary>
/// Adds two doubles and returns the result.
/// </summary>
/// <returns>
/// The sum of two doubles.
/// </returns>
/// <exception cref="System.OverflowException">Thrown when one parameter is max
/// and the other is greater than zero.</exception>
/// See <see cref="Math.Add(int, int)"/> to add integers.
public static double Add(double a, double b)
{
if ((a == double.MaxValue && b > 0) || (b == double.MaxValue && a > 0))
throw new System.OverflowException();
return a + b;
}
}
The cref is a required attribute that represents a reference to a type or its member that is available from the
current compilation environment. This can be any type defined in the project or a referenced assembly.
<seealso>
You use the <seealso> tag in the same way you do the <see> tag. The only difference is that its content is typically
placed in a "See Also" section. Here we'll add a seealso tag on the integer Add method to reference other
methods in the class that accept integer parameters:
/*
The main Math class
Contains all methods for performing basic math functions
*/
/// <summary>
/// The main <c>Math</c> class.
/// Contains all methods for performing basic math functions.
/// </summary>
public class Math
{
/// <summary>
/// Adds two integers and returns the result.
/// </summary>
/// <returns>
/// The sum of two integers.
/// </returns>
/// <example>
/// <code>
/// int c = Math.Add(4, 5);
/// if (c > 10)
/// {
/// Console.WriteLine(c);
/// }
/// </code>
/// </example>
/// <exception cref="System.OverflowException">Thrown when one parameter is max
/// and the other is greater than 0.</exception>
/// See <see cref="Math.Add(double, double)"/> to add doubles.
/// <seealso cref="Math.Subtract(int, int)"/>
/// <seealso cref="Math.Multiply(int, int)"/>
/// <seealso cref="Math.Divide(int, int)"/>
public static int Add(int a, int b)
{
if ((a == int.MaxValue && b > 0) || (b == int.MaxValue && a > 0))
throw new System.OverflowException();
return a + b;
}
}
The cref attribute represents a reference to a type or its member that is available from the current compilation
environment. This can be any type defined in the project or a referenced assembly.
<param>
You use the <param> tag to describe a method's parameters. Here's an example on the double Add method: The
parameter the tag describes is specified in the required name attribute.
/*
The main Math class
Contains all methods for performing basic math functions
*/
/// <summary>
/// The main <c>Math</c> class.
/// Contains all methods for performing basic math functions.
/// </summary>
public class Math
{
/// <summary>
/// Adds two doubles and returns the result.
/// </summary>
/// <returns>
/// The sum of two doubles.
/// </returns>
/// <exception cref="System.OverflowException">Thrown when one parameter is max
/// and the other is greater than zero.</exception>
/// See <see cref="Math.Add(int, int)"/> to add integers.
/// <param name="a">A double precision number.</param>
/// <param name="b">A double precision number.</param>
public static double Add(double a, double b)
{
if ((a == double.MaxValue && b > 0) || (b == double.MaxValue && a > 0))
throw new System.OverflowException();
return a + b;
}
}
<typeparam>
You use <typeparam> tag just like the <param> tag but for generic type or method declarations to describe a
generic parameter. Add a quick generic method to your Math class to check if one quantity is greater than another.
/*
The main Math class
Contains all methods for performing basic math functions
*/
/// <summary>
/// The main <c>Math</c> class.
/// Contains all methods for performing basic math functions.
/// </summary>
public class Math
{
/// <summary>
/// Checks if an IComparable is greater than another.
/// </summary>
/// <typeparam name="T">A type that inherits from the IComparable interface.</typeparam>
public static bool GreaterThan<T>(T a, T b) where T : IComparable
{
return a.CompareTo(b) > 0;
}
}
<paramref>
Sometimes you might be in the middle of describing what a method does in what could be a <summary> tag, and
you might want to make a reference to a parameter. The <paramref> tag is great for just this. Let's update the
summary of our double based Add method. Like the <param> tag, the parameter name is specified in the
required name attribute.
/*
The main Math class
Contains all methods for performing basic math functions
*/
/// <summary>
/// The main <c>Math</c> class.
/// Contains all methods for performing basic math functions.
/// </summary>
public class Math
{
/// <summary>
/// Adds two doubles <paramref name="a"/> and <paramref name="b"/> and returns the result.
/// </summary>
/// <returns>
/// The sum of two doubles.
/// </returns>
/// <exception cref="System.OverflowException">Thrown when one parameter is max
/// and the other is greater than zero.</exception>
/// See <see cref="Math.Add(int, int)"/> to add integers.
/// <param name="a">A double precision number.</param>
/// <param name="b">A double precision number.</param>
public static double Add(double a, double b)
{
if ((a == double.MaxValue && b > 0) || (b == double.MaxValue && a > 0))
throw new System.OverflowException();
return a + b;
}
}
<typeparamref>
You use <typeparamref> tag just like the <paramref> tag but for generic type or method declarations to describe a
generic parameter. You can use the same generic method you previously created.
/*
The main Math class
Contains all methods for performing basic math functions
*/
/// <summary>
/// The main <c>Math</c> class.
/// Contains all methods for performing basic math functions.
/// </summary>
public class Math
{
/// <summary>
/// Checks if an IComparable <typeparamref name="T"/> is greater than another.
/// </summary>
/// <typeparam name="T">A type that inherits from the IComparable interface.</typeparam>
public static bool GreaterThan<T>(T a, T b) where T : IComparable
{
return a.CompareTo(b) > 0;
}
}
<list>
You use the <list> tag to format documentation information as an ordered list, unordered list, or table. Make an
unordered list of every math operation your Math library supports.
/*
The main Math class
Contains all methods for performing basic math functions
*/
/// <summary>
/// The main <c>Math</c> class.
/// Contains all methods for performing basic math functions.
/// <list type="bullet">
/// <item>
/// <term>Add</term>
/// <description>Addition Operation</description>
/// </item>
/// <item>
/// <term>Subtract</term>
/// <description>Subtraction Operation</description>
/// </item>
/// <item>
/// <term>Multiply</term>
/// <description>Multiplication Operation</description>
/// </item>
/// <item>
/// <term>Divide</term>
/// <description>Division Operation</description>
/// </item>
/// </list>
/// </summary>
public class Math
{
}
You can make an ordered list or table by changing the type attribute to number or table , respectively.
<inheritdoc>
You can use the <inheritdoc> tag to inherit XML comments from base classes, interfaces, and similar methods. This
eliminates unwanted copying and pasting of duplicate XML comments and automatically keeps XML comments
synchronized.
/*
The IMath interface
The main Math class
Contains all methods for performing basic math functions
*/
/// <summary>
/// This is the IMath interface.
/// </summary>
public interface IMath
{
}
/// <inheritdoc/>
public class Math : IMath
{
}
/*
The main Math class
Contains all methods for performing basic math functions
Contains all methods for performing basic math functions
*/
/// <summary>
/// The main <c>Math</c> class.
/// Contains all methods for performing basic math functions.
/// <list type="bullet">
/// <item>
/// <term>Add</term>
/// <description>Addition Operation</description>
/// </item>
/// <item>
/// <term>Subtract</term>
/// <description>Subtraction Operation</description>
/// </item>
/// <item>
/// <term>Multiply</term>
/// <description>Multiplication Operation</description>
/// </item>
/// <item>
/// <term>Divide</term>
/// <description>Division Operation</description>
/// </item>
/// </list>
/// </summary>
/// <remarks>
/// <para>This class can add, subtract, multiply and divide.</para>
/// <para>These operations can be performed on both integers and doubles.</para>
/// </remarks>
public class Math
{
// Adds two integers and returns the result
/// <summary>
/// Adds two integers <paramref name="a"/> and <paramref name="b"/> and returns the result.
/// </summary>
/// <returns>
/// The sum of two integers.
/// </returns>
/// <example>
/// <code>
/// int c = Math.Add(4, 5);
/// if (c > 10)
/// {
/// Console.WriteLine(c);
/// }
/// </code>
/// </example>
/// <exception cref="System.OverflowException">Thrown when one parameter is max
/// and the other is greater than 0.</exception>
/// See <see cref="Math.Add(double, double)"/> to add doubles.
/// <seealso cref="Math.Subtract(int, int)"/>
/// <seealso cref="Math.Multiply(int, int)"/>
/// <seealso cref="Math.Divide(int, int)"/>
/// <param name="a">An integer.</param>
/// <param name="b">An integer.</param>
public static int Add(int a, int b)
{
// If any parameter is equal to the max value of an integer
// and the other is greater than zero
if ((a == int.MaxValue && b > 0) || (b == int.MaxValue && a > 0))
throw new System.OverflowException();
return a + b;
}
return a + b;
}
From your code, you can generate a detailed documentation website complete with clickable cross-references. But
you're faced with another problem: your code has become hard to read. There's so much information to sift through
that this is going to be a nightmare for any developer who wants to contribute to this code. Thankfully there's an
XML tag that can help you deal with this:
<include>
The <include> tag lets you refer to comments in a separate XML file that describe the types and members in your
source code, as opposed to placing documentation comments directly in your source code file.
Now you're going to move all your XML tags into a separate XML file named docs.xml . Feel free to name the file
whatever you want.
<docs>
<members name="math">
<Math>
<summary>
The main <c>Math</c> class.
Contains all methods for performing basic math functions.
</summary>
<remarks>
<para>This class can add, subtract, multiply and divide.</para>
<para>These operations can be performed on both integers and doubles.</para>
</remarks>
</Math>
<AddInt>
<summary>
Adds two integers <paramref name="a"/> and <paramref name="b"/> and returns the result.
</summary>
<returns>
The sum of two integers.
</returns>
<example>
<code>
int c = Math.Add(4, 5);
if (c > 10)
{
Console.WriteLine(c);
}
</code>
</example>
<exception cref="System.OverflowException">Thrown when one parameter is max
and the other is greater than 0.</exception>
See <see cref="Math.Add(double, double)"/> to add doubles.
<seealso cref="Math.Subtract(int, int)"/>
<seealso cref="Math.Multiply(int, int)"/>
<seealso cref="Math.Divide(int, int)"/>
<param name="a">An integer.</param>
<param name="b">An integer.</param>
</AddInt>
<AddDouble>
<summary>
Adds two doubles <paramref name="a"/> and <paramref name="b"/> and returns the result.
</summary>
<returns>
The sum of two doubles.
</returns>
<example>
<code>
double c = Math.Add(4.5, 5.4);
if (c > 10)
{
Console.WriteLine(c);
}
</code>
</example>
<exception cref="System.OverflowException">Thrown when one parameter is max
and the other is greater than 0.</exception>
See <see cref="Math.Add(int, int)"/> to add integers.
<seealso cref="Math.Subtract(double, double)"/>
<seealso cref="Math.Multiply(double, double)"/>
<seealso cref="Math.Divide(double, double)"/>
<param name="a">A double precision number.</param>
<param name="b">A double precision number.</param>
</AddDouble>
<SubtractInt>
<summary>
Subtracts <paramref name="b"/> from <paramref name="a"/> and returns the result.
</summary>
<returns>
The difference between two integers.
</returns>
<example>
<code>
int c = Math.Subtract(4, 5);
if (c > 1)
{
Console.WriteLine(c);
}
</code>
</example>
See <see cref="Math.Subtract(double, double)"/> to subtract doubles.
<seealso cref="Math.Add(int, int)"/>
<seealso cref="Math.Multiply(int, int)"/>
<seealso cref="Math.Divide(int, int)"/>
<param name="a">An integer.</param>
<param name="b">An integer.</param>
</SubtractInt>
<SubtractDouble>
<summary>
Subtracts a double <paramref name="b"/> from another double <paramref name="a"/> and returns the
result.
</summary>
<returns>
The difference between two doubles.
</returns>
<example>
<code>
double c = Math.Subtract(4.5, 5.4);
if (c > 1)
{
Console.WriteLine(c);
}
</code>
</example>
See <see cref="Math.Subtract(int, int)"/> to subtract integers.
<seealso cref="Math.Add(double, double)"/>
<seealso cref="Math.Multiply(double, double)"/>
<seealso cref="Math.Divide(double, double)"/>
<param name="a">A double precision number.</param>
<param name="b">A double precision number.</param>
</SubtractDouble>
<MultiplyInt>
<summary>
Multiplies two integers <paramref name="a"/> and <paramref name="b"/> and returns the result.
</summary>
<returns>
The product of two integers.
</returns>
<example>
<code>
int c = Math.Multiply(4, 5);
if (c > 100)
{
Console.WriteLine(c);
}
</code>
</example>
See <see cref="Math.Multiply(double, double)"/> to multiply doubles.
<seealso cref="Math.Add(int, int)"/>
<seealso cref="Math.Subtract(int, int)"/>
<seealso cref="Math.Divide(int, int)"/>
<param name="a">An integer.</param>
<param name="a">An integer.</param>
<param name="b">An integer.</param>
</MultiplyInt>
<MultiplyDouble>
<summary>
Multiplies two doubles <paramref name="a"/> and <paramref name="b"/> and returns the result.
</summary>
<returns>
The product of two doubles.
</returns>
<example>
<code>
double c = Math.Multiply(4.5, 5.4);
if (c > 100.0)
{
Console.WriteLine(c);
}
</code>
</example>
See <see cref="Math.Multiply(int, int)"/> to multiply integers.
<seealso cref="Math.Add(double, double)"/>
<seealso cref="Math.Subtract(double, double)"/>
<seealso cref="Math.Divide(double, double)"/>
<param name="a">A double precision number.</param>
<param name="b">A double precision number.</param>
</MultiplyDouble>
<DivideInt>
<summary>
Divides an integer <paramref name="a"/> by another integer <paramref name="b"/> and returns the
result.
</summary>
<returns>
The quotient of two integers.
</returns>
<example>
<code>
int c = Math.Divide(4, 5);
if (c > 1)
{
Console.WriteLine(c);
}
</code>
</example>
<exception cref="System.DivideByZeroException">Thrown when <paramref name="b"/> is equal to 0.
</exception>
See <see cref="Math.Divide(double, double)"/> to divide doubles.
<seealso cref="Math.Add(int, int)"/>
<seealso cref="Math.Subtract(int, int)"/>
<seealso cref="Math.Multiply(int, int)"/>
<param name="a">An integer dividend.</param>
<param name="b">An integer divisor.</param>
</DivideInt>
<DivideDouble>
<summary>
Divides a double <paramref name="a"/> by another double <paramref name="b"/> and returns the
result.
</summary>
<returns>
The quotient of two doubles.
</returns>
<example>
<code>
double c = Math.Divide(4.5, 5.4);
if (c > 1.0)
{
Console.WriteLine(c);
}
</code>
</example>
<exception cref="System.DivideByZeroException">Thrown when <paramref name="b"/> is equal to 0.
<exception cref="System.DivideByZeroException">Thrown when <paramref name="b"/> is equal to 0.
</exception>
See <see cref="Math.Divide(int, int)"/> to divide integers.
<seealso cref="Math.Add(double, double)"/>
<seealso cref="Math.Subtract(double, double)"/>
<seealso cref="Math.Multiply(double, double)"/>
<param name="a">A double precision dividend.</param>
<param name="b">A double precision divisor.</param>
</DivideDouble>
</members>
</docs>
In the above XML, each member's documentation comments appear directly inside a tag named after what they do.
You can choose your own strategy. Now that you have your XML comments in a separate file, let's see how your
code can be made more readable by using the <include> tag:
/*
The main Math class
Contains all methods for performing basic math functions
*/
/// <include file='docs.xml' path='docs/members[@name="math"]/Math/*'/>
public class Math
{
// Adds two integers and returns the result
/// <include file='docs.xml' path='docs/members[@name="math"]/AddInt/*'/>
public static int Add(int a, int b)
{
// If any parameter is equal to the max value of an integer
// and the other is greater than zero
if ((a == int.MaxValue && b > 0) || (b == int.MaxValue && a > 0))
throw new System.OverflowException();
return a + b;
}
return a + b;
}
And there you have it: our code is back to being readable, and no documentation information has been lost.
The file attribute represents the name of the XML file containing the documentation.
The path attribute represents an XPath query to the tag name present in the specified file .
The name attribute represents the name specifier in the tag that precedes the comments.
The id attribute, which can be used in place of name , represents the ID for the tag that precedes the comments.
User-defined tags
All the tags outlined above represent those that are recognized by the C# compiler. However, a user is free to define
their own tags. Tools like Sandcastle bring support for extra tags like <event> and <note>, and even support
documenting namespaces. Custom or in-house documentation generation tools can also be used with the standard
tags and multiple output formats from HTML to PDF can be supported.
Recommendations
Documenting code is recommended for many reasons. What follows are some best practices, general use case
scenarios, and things that you should know when using XML documentation tags in your C# code.
For the sake of consistency, all publicly visible types and their members should be documented. If you must do
it, do it all.
Private members can also be documented using XML comments. However, this exposes the inner (potentially
confidential) workings of your library.
At a bare minimum, types and their members should have a <summary> tag because its content is needed for
IntelliSense.
Documentation text should be written using complete sentences ending with full stops.
Partial classes are fully supported, and documentation information will be concatenated into a single entry for
that type.
The compiler verifies the syntax of the <exception> , <include> , <param> , <see> , <seealso> , and <typeparam>
tags.
The compiler validates the parameters that contain file paths and references to other parts of the code.
See also
XML Documentation Comments (C# Programming Guide)
Recommended Tags for Documentation Comments (C# Programming Guide)
Versioning in C#
4/20/2020 • 5 minutes to read • Edit Online
In this tutorial you'll learn what versioning means in .NET. You'll also learn the factors to consider when versioning
your library as well as upgrading to a new version of a library.
Authoring Libraries
As a developer who has created .NET libraries for public use, you've most likely been in situations where you have
to roll out new updates. How you go about this process matters a lot as you need to ensure that there's a seamless
transition of existing code to the new version of your library. Here are several things to consider when creating a
new release:
Semantic Versioning
Semantic versioning (SemVer for short) is a naming convention applied to versions of your library to signify
specific milestone events. Ideally, the version information you give your library should help developers determine
the compatibility with their projects that make use of older versions of that same library.
The most basic approach to SemVer is the 3 component format MAJOR.MINOR.PATCH , where:
MAJOR is incremented when you make incompatible API changes
MINOR is incremented when you add functionality in a backwards-compatible manner
PATCH is incremented when you make backwards-compatible bug fixes
There are also ways to specify other scenarios like pre-release versions etc. when applying version information to
your .NET library.
Backwards Compatibility
As you release new versions of your library, backwards compatibility with previous versions will most likely be one
of your major concerns. A new version of your library is source compatible with a previous version if code that
depends on the previous version can, when recompiled, work with the new version. A new version of your library is
binary compatible if an application that depended on the old version can, without recompilation, work with the new
version.
Here are some things to consider when trying to maintain backwards compatibility with older versions of your
library:
Virtual methods: When you make a virtual method non-virtual in your new version it means that projects that
override that method will have to be updated. This is a huge breaking change and is strongly discouraged.
Method signatures: When updating a method behavior requires you to change its signature as well, you should
instead create an overload so that code calling into that method will still work. You can always manipulate the
old method signature to call into the new method signature so that implementation remains consistent.
Obsolete attribute: You can use this attribute in your code to specify classes or class members that are
deprecated and likely to be removed in future versions. This ensures developers utilizing your library are better
prepared for breaking changes.
Optional Method Arguments: When you make previously optional method arguments compulsory or change
their default value then all code that does not supply those arguments will need to be updated.
NOTE
Making compulsory arguments optional should have very little effect especially if it doesn't change the method's behavior.
The easier you make it for your users to upgrade to the new version of your library, the more likely that they will
upgrade sooner.
Application Configuration File
As a .NET developer there's a very high chance you've encountered the app.config file present in most project
types. This simple configuration file can go a long way into improving the rollout of new updates. You should
generally design your libraries in such a way that information that is likely to change regularly is stored in the
app.config file, this way when such information is updated, the config file of older versions just needs to be
replaced with the new one without the need for recompilation of the library.
Consuming Libraries
As a developer that consumes .NET libraries built by other developers you're most likely aware that a new version
of a library might not be fully compatible with your project and you might often find yourself having to update
your code to work with those changes.
Lucky for you, C# and the .NET ecosystem comes with features and techniques that allow us to easily update our
app to work with new versions of libraries that might introduce breaking changes.
Assembly Binding Redirection
You can use the app.config file to update the version of a library your app uses. By adding what is called a binding
redirect, you can use the new library version without having to recompile your app. The following example shows
how you would update your app's app.config file to use the 1.0.1 patch version of ReferencedLibrary instead of
the 1.0.0 version it was originally compiled with.
<dependentAssembly>
<assemblyIdentity name="ReferencedLibrary" publicKeyToken="32ab4ba45e0a69a1" culture="en-us" />
<bindingRedirect oldVersion="1.0.0" newVersion="1.0.1" />
</dependentAssembly>
NOTE
This approach will only work if the new version of ReferencedLibrary is binary compatible with your app. See the
Backwards Compatibility section above for changes to look out for when determining compatibility.
new
You use the new modifier to hide inherited members of a base class. This is one way derived classes can respond to
updates in base classes.
Take the following example:
public class BaseClass
{
public void MyMethod()
{
Console.WriteLine("A base method");
}
}
b.MyMethod();
d.MyMethod();
}
Output
A base method
A derived method
From the example above you can see how DerivedClass hides the MyMethod method present in BaseClass . This
means that when a base class in the new version of a library adds a member that already exists in your derived
class, you can simply use the new modifier on your derived class member to hide the base class member.
When no new modifier is specified, a derived class will by default hide conflicting members in a base class,
although a compiler warning will be generated the code will still compile. This means that simply adding new
members to an existing class makes that new version of your library both source and binary compatible with code
that depends on it.
override
The override modifier means a derived implementation extends the implementation of a base class member
rather than hides it. The base class member needs to have the virtual modifier applied to it.
public class MyBaseClass
{
public virtual string MethodOne()
{
return "Method One";
}
}
Output
The override modifier is evaluated at compile time and the compiler will throw an error if it doesn't find a virtual
member to override.
Your knowledge of the discussed techniques and your understanding of the situations in which to use them, will go
a long way towards easing the transition between versions of a library.
How to (C#)
5/5/2020 • 3 minutes to read • Edit Online
In the How to section of the C# Guide, you can find quick answers to common questions. In some cases, articles
may be listed in multiple sections. We wanted to make them easy to find for multiple search paths.
General C# concepts
There are several tips and tricks that are common C# developer practices:
Initialize objects using an object initializer.
Learn the differences between passing a struct and a class to a method.
Use operator overloading.
Implement and call a custom extension method.
Even C# programmers may want to use the My namespace from Visual Basic.
Create a new method for an enum type using extension methods.
Class and struct members
You create classes and structs to implement your program. These techniques are commonly used when writing
classes or structs.
Declare auto implemented properties.
Declare and use read/write properties.
Define constants.
Override the ToString method to provide string output.
Define abstract properties.
Use the xml documentation features to document your code.
Explicitly implement interface members to keep your public interface concise.
Explicitly implement members of two interfaces.
Working with collections
These articles help you work with collections of data.
Initialize a dictionary with a collection initializer.
Exception handling
.NET programs report that methods did not successfully complete their work by throwing exceptions. In these
articles you'll learn to work with exceptions.
Handle exceptions using try and catch .
Cleanup resources using finally clauses.
Recover from non-CLS (Common Language Specification) exceptions.
LINQ practices
LINQ enables you to write code to query any data source that supports the LINQ query expression pattern. These
articles help you understand the pattern and work with different data sources.
Query a collection.
Use lambda expressions in a query.
Use var in query expressions.
Return subsets of element properties from a query.
Write queries with complex filtering.
Sort elements of a data source.
Sort elements on multiple keys.
Control the type of a projection.
Count occurrences of a value in a source sequence.
Calculate intermediate values.
Merge data from multiple sources.
Find the set difference between two sequences.
Debug empty query results.
Add custom methods to LINQ queries.
The String.Split method creates an array of substrings by splitting the input string based on one or more delimiters.
This method is often the easiest way to separate a string on word boundaries. It's also used to split strings on other
specific characters or strings.
NOTE
The C# examples in this article run in the Try.NET inline code runner and playground. Select the Run button to run an
example in an interactive window. Once you execute the code, you can modify it and run the modified code by selecting Run
again. The modified code either runs in the interactive window or, if compilation fails, the interactive window displays all C#
compiler error messages.
The following code splits a common phrase into an array of strings for each word.
string phrase = "The quick brown fox jumps over the lazy dog.";
string[] words = phrase.Split(' ');
Every instance of a separator character produces a value in the returned array. Consecutive separator characters
produce the empty string as a value in the returned array. You can see how an empty string is created in the
following example, which uses the space character as a separator.
string phrase = "The quick brown fox jumps over the lazy dog.";
string[] words = phrase.Split(' ');
This behavior makes it easier for formats like comma-separated values (CSV) files representing tabular data.
Consecutive commas represent a blank column.
You can pass an optional StringSplitOptions.RemoveEmptyEntries parameter to exclude any empty strings in the
returned array. For more complicated processing of the returned collection, you can use LINQ to manipulate the
result sequence.
String.Split can use multiple separator characters. The following example uses spaces, commas, periods, colons,
and tabs as separating characters, which are passed to Split in an array . The loop at the bottom of the code
displays each of the words in the returned array.
char[] delimiterChars = { ' ', ',', '.', ':', '\t' };
Consecutive instances of any separator produce the empty string in the output array:
String.Split can take an array of strings (character sequences that act as separators for parsing the target string,
instead of single characters).
See also
C# programming guide
Strings
.NET regular expressions
How to concatenate multiple strings (C# Guide)
9/3/2020 • 3 minutes to read • Edit Online
Concatenation is the process of appending one string to the end of another string. You concatenate strings by
using the + operator. For string literals and string constants, concatenation occurs at compile time; no run-time
concatenation occurs. For string variables, concatenation occurs only at run time.
NOTE
The C# examples in this article run in the Try.NET inline code runner and playground. Select the Run button to run an
example in an interactive window. Once you execute the code, you can modify it and run the modified code by selecting Run
again. The modified code either runs in the interactive window or, if compilation fails, the interactive window displays all C#
compiler error messages.
The following example uses concatenation to split a long string literal into smaller strings in order to improve
readability in the source code. These parts are concatenated into a single string at compile time. There is no run-
time performance cost regardless of the number of strings involved.
System.Console.WriteLine(text);
To concatenate string variables, you can use the + or += operators, string interpolation or the String.Format,
String.Concat, String.Join or StringBuilder.Append methods. The + operator is easy to use and makes for intuitive
code. Even if you use several + operators in one statement, the string content is copied only once. The following
code shows examples of using the + and += operators to concatenate strings:
In some expressions, it's easier to concatenate strings using string interpolation, as the following code shows:
string userName = "<Type your name here>";
string date = DateTime.Today.ToShortDateString();
NOTE
In string concatenation operations, the C# compiler treats a null string the same as an empty string.
Other method to concatenate strings is String.Format. This method works well when you are building a string from
a small number of component strings.
In other cases, you may be combining strings in a loop where you don't know how many source strings you're
combining, and the actual number of source strings may be large. The StringBuilder class was designed for these
scenarios. The following code uses the Append method of the StringBuilder class to concatenate strings.
You can read more about the reasons to choose string concatenation or the StringBuilder class.
Another option to join strings from a collection is to use String.Concat method. Use String.Join method if source
strings should be separated by a delimiter. The following code combines an array of words using both methods:
string[] words = { "The", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog." };
At last, you can use LINQ and the Enumerable.Aggregate method to join strings from a collection. This method
combines the source strings using a lambda expression. The lambda expression does the work to add each string
to the existing accumulation. The following example combines an array of words by adding a space between each
word in the array:
string[] words = { "The", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog." };
See also
String
StringBuilder
C# programming guide
Strings
How to search strings
9/3/2020 • 4 minutes to read • Edit Online
You can use two main strategies to search for text in strings. Methods of the String class search for specific text.
Regular expressions search for patterns in text.
NOTE
The C# examples in this article run in the Try.NET inline code runner and playground. Select the Run button to run an
example in an interactive window. Once you execute the code, you can modify it and run the modified code by selecting Run
again. The modified code either runs in the interactive window or, if compilation fails, the interactive window displays all C#
compiler error messages.
The string type, which is an alias for the System.String class, provides a number of useful methods for searching
the contents of a string. Among them are Contains, StartsWith, EndsWith, IndexOf, LastIndexOf. The
System.Text.RegularExpressions.Regex class provides a rich vocabulary to search for patterns in text. In this article,
you learn these techniques and how to choose the best method for your needs.
string factMessage = "Extension methods have all the capabilities of regular static methods.";
// For user input and strings that will be displayed to the end user,
// use the StringComparison parameter on methods that have it to specify how to match strings.
bool ignoreCaseSearchResult = factMessage.StartsWith("extension",
System.StringComparison.CurrentCultureIgnoreCase);
Console.WriteLine($"Starts with \"extension\"? {ignoreCaseSearchResult} (ignoring case)");
The preceding example demonstrates an important point for using these methods. Searches are case-sensitive
by default. You use the StringComparison.CurrentCultureIgnoreCase enumeration value to specify a case-
insensitive search.
PAT T ERN M EA N IN G
string[] sentences =
{
"Put the water over there.",
"They're quite thirsty.",
"Their water bottles broke."
};
if (System.Text.RegularExpressions.Regex.IsMatch(s, sPattern,
System.Text.RegularExpressions.RegexOptions.IgnoreCase))
{
Console.WriteLine($" (match for '{sPattern}' found)");
}
else
{
Console.WriteLine();
}
}
TIP
The string methods are usually better choices when you are searching for an exact string. Regular expressions are better
when you are searching for some pattern in a source string.
PAT T ERN M EA N IN G
if (System.Text.RegularExpressions.Regex.IsMatch(s, sPattern))
{
Console.WriteLine(" - valid");
}
else
{
Console.WriteLine(" - invalid");
}
}
This single search pattern matches many valid strings. Regular expressions are better to search for or validate
against a pattern, rather than a single text string.
See also
C# programming guide
Strings
LINQ and strings
System.Text.RegularExpressions.Regex
.NET Framework regular expressions
Regular expression language - quick reference
Best practices for using strings in .NET
How to modify string contents in C#
9/3/2020 • 5 minutes to read • Edit Online
This article demonstrates several techniques to produce a string by modifying an existing string . All the
techniques demonstrated return the result of the modifications as a new string object. To demonstrate that the
original and modified strings are distinct instances, the examples store the result in a new variable. You can
examine the original string and the new, modified string when you run each example.
NOTE
The C# examples in this article run in the Try.NET inline code runner and playground. Select the Run button to run an
example in an interactive window. Once you execute the code, you can modify it and run the modified code by selecting Run
again. The modified code either runs in the interactive window or, if compilation fails, the interactive window displays all C#
compiler error messages.
There are several techniques demonstrated in this article. You can replace existing text. You can search for patterns
and replace matching text with other text. You can treat a string as a sequence of characters. You can also use
convenience methods that remove white space. Choose the techniques that most closely match your scenario.
Replace text
The following code creates a new string by replacing existing text with a substitute.
The preceding code demonstrates this immutable property of strings. You can see in the preceding example that
the original string, source , is not modified. The String.Replace method creates a new string containing the
modifications.
The Replace method can replace either strings or single characters. In both cases, every occurrence of the sought
text is replaced. The following example replaces all ' ' characters with '_':
The source string is unchanged, and a new string is returned with the replacement.
Remove text
You can remove text from a string using the String.Remove method. This method removes a number of characters
starting at a specific index. The following example shows how to use String.IndexOf followed by Remove to remove
text from a string:
The StringBuilder.ToString method returns an immutable string with the contents in the StringBuilder object.
string phrase = "The quick brown fox jumps over the fence";
Console.WriteLine(phrase);
Console.WriteLine(result);
You could modify a string in a fixed block with unsafe code, but it is strongly discouraged to modify the string
content after a string is created. Doing so will break things in unpredictable ways. For example, if someone interns
a string that has the same content as yours, they'll get your copy and won't expect that you are modifying their
string.
See also
.NET Framework regular expressions
Regular expression language - quick reference
How to compare strings in C#
9/3/2020 • 11 minutes to read • Edit Online
You compare strings to answer one of two questions: "Are these two strings equal?" or "In what order should these
strings be placed when sorting them?"
Those two questions are complicated by factors that affect string comparisons:
You can choose an ordinal or linguistic comparison.
You can choose if case matters.
You can choose culture-specific comparisons.
Linguistic comparisons are culture and platform-dependent.
NOTE
The C# examples in this article run in the Try.NET inline code runner and playground. Select the Run button to run an
example in an interactive window. Once you execute the code, you can modify it and run the modified code by selecting Run
again. The modified code either runs in the interactive window or, if compilation fails, the interactive window displays all C#
compiler error messages.
When you compare strings, you define an order among them. Comparisons are used to sort a sequence of strings.
Once the sequence is in a known order, it is easier to search, both for software and for humans. Other comparisons
may check if strings are the same. These sameness checks are similar to equality, but some differences, such as
case differences, may be ignored.
perform a case-sensitive ordinal comparison and, if necessary, use the current culture. The following example
demonstrates that:
Console.WriteLine($"Using == says that <{root}> and <{root2}> are {(root == root2 ? "equal" : "not equal")}");
The default ordinal comparison doesn't take linguistic rules into account when comparing strings. It compares the
binary value of each Char object in two strings. As a result, the default ordinal comparison is also case-sensitive.
The test for equality with String.Equals and the == and != operators differs from string comparison using the
String.CompareTo and Compare(String, String) methods. While the tests for equality perform a case-sensitive
ordinal comparison, the comparison methods perform a case-sensitive, culture-sensitive comparison using the
current culture. Because the default comparison methods often perform different types of comparisons, we
recommend that you always make the intent of your code clear by calling an overload that explicitly specifies the
type of comparison to perform.
Console.WriteLine($"Ordinal ignore case: <{root}> and <{root2}> are {(result ? "equal." : "not equal.")}");
Console.WriteLine($"Ordinal static ignore case: <{root}> and <{root2}> are {(areEqual ? "equal." : "not
equal.")}");
if (comparison < 0)
Console.WriteLine($"<{root}> is less than <{root2}>");
else if (comparison > 0)
Console.WriteLine($"<{root}> is greater than <{root2}>");
else
Console.WriteLine($"<{root}> and <{root2}> are equivalent in order");
When performing a case-insensitive ordinal comparison, these methods use the casing conventions of the
invariant culture.
Linguistic comparisons
Strings can also be ordered using linguistic rules for the current culture. This is sometimes referred to as "word
sort order." When you perform a linguistic comparison, some nonalphanumeric Unicode characters might have
special weights assigned. For example, the hyphen "-" may have a small weight assigned to it so that "co-op" and
"coop" appear next to each other in sort order. In addition, some Unicode characters may be equivalent to a
sequence of Char instances. The following example uses the phrase "They dance in the street." in German with the
"ss" (U+0073 U+0073) in one string and 'ß' (U+00DF) in another. Linguistically (in Windows), "ss" is equal to the
German Esszet: 'ß' character in both the "en-US" and "de-DE" cultures.
string first = "Sie tanzen auf der Straße.";
string second = "Sie tanzen auf der Strasse.";
showComparison(word, words);
showComparison(word, other);
showComparison(words, other);
void showComparison(string one, string two)
{
int compareLinguistic = String.Compare(one, two, StringComparison.InvariantCulture);
int compareOrdinal = String.Compare(one, two, StringComparison.Ordinal);
if (compareLinguistic < 0)
Console.WriteLine($"<{one}> is less than <{two}> using invariant culture");
else if (compareLinguistic > 0)
Console.WriteLine($"<{one}> is greater than <{two}> using invariant culture");
else
Console.WriteLine($"<{one}> and <{two}> are equivalent in order using invariant culture");
if (compareOrdinal < 0)
Console.WriteLine($"<{one}> is less than <{two}> using ordinal comparison");
else if (compareOrdinal > 0)
Console.WriteLine($"<{one}> is greater than <{two}> using ordinal comparison");
else
Console.WriteLine($"<{one}> and <{two}> are equivalent in order using ordinal comparison");
}
This sample demonstrates the operating system-dependent nature of linguistic comparisons. The host for the
interactive window is a Linux host. The linguistic and ordinal comparisons produce the same results. If you run this
same sample on a Windows host, you see the following output:
On Windows, the sort order of "cop", "coop", and "co-op" change when you change from a linguistic comparison
to an ordinal comparison. The two German sentences also compare differently using the different comparison
types.
Culture-sensitive comparisons are typically used to compare and sort strings input by users with other strings
input by users. The characters and sorting conventions of these strings might vary depending on the locale of the
user's computer. Even strings that contain identical characters might sort differently depending on the culture of
the current thread. In addition, try this sample code locally on a Windows machine, and you'll get the following
results:
Linguistic comparisons are dependent on the current culture, and are OS dependent. Take that into account when
you work with string comparisons.
Console.WriteLine("Non-sorted order:");
foreach (string s in lines)
{
Console.WriteLine($" {s}");
}
Console.WriteLine("\n\rSorted order:");
Once the array is sorted, you can search for entries using a binary search. A binary search starts in the middle of
the collection to determine which half of the collection would contain the sought string. Each subsequent
comparison subdivides the remaining part of the collection in half. The array is sorted using the
StringComparer.CurrentCulture. The local function ShowWhere displays information about where the string was
found. If the string wasn't found, the returned value indicates where it would be if it were found.
string[] lines = new string[]
{
@"c:\public\textfile.txt",
@"c:\public\textFile.TXT",
@"c:\public\Text.txt",
@"c:\public\testfile2.txt"
};
Array.Sort(lines, StringComparer.CurrentCulture);
if (index == 0)
Console.Write("beginning of sequence and ");
else
Console.Write($"{array[index - 1]} and ");
if (index == array.Length)
Console.WriteLine("end of sequence.");
else
Console.WriteLine($"{array[index]}.");
}
else
{
Console.WriteLine($"Found at index {index}.");
}
}
Console.WriteLine("Non-sorted order:");
foreach (string s in lines)
{
Console.WriteLine($" {s}");
}
Console.WriteLine("\n\rSorted order:");
Once sorted, the list of strings can be searched using a binary search. The following sample shows how to search
the sorted listed using the same comparison function. The local function ShowWhere shows where the sought text is
or would be:
List<string> lines = new List<string>
{
@"c:\public\textfile.txt",
@"c:\public\textFile.TXT",
@"c:\public\Text.txt",
@"c:\public\testfile2.txt"
};
lines.Sort((left, right) => left.CompareTo(right));
if (index == 0)
Console.Write("beginning of sequence and ");
else
Console.Write($"{collection[index - 1]} and ");
if (index == collection.Count)
Console.WriteLine("end of sequence.");
else
Console.WriteLine($"{collection[index]}.");
}
else
{
Console.WriteLine($"Found at index {index}.");
}
}
Always make sure to use the same type of comparison for sorting and searching. Using different comparison types
for sorting and searching produces unexpected results.
Collection classes such as System.Collections.Hashtable, System.Collections.Generic.Dictionary<TKey,TValue>, and
System.Collections.Generic.List<T> have constructors that take a System.StringComparer parameter when the type
of the elements or keys is string . In general, you should use these constructors whenever possible, and specify
either StringComparer.Ordinal or StringComparer.OrdinalIgnoreCase.
if (String.ReferenceEquals(a, b))
Console.WriteLine("a and b are interned.");
else
Console.WriteLine("a and b are not interned.");
string c = String.Copy(a);
if (String.ReferenceEquals(a, c))
Console.WriteLine("a and c are interned.");
else
Console.WriteLine("a and c are not interned.");
NOTE
When you test for equality of strings, you should use the methods that explicitly specify what kind of comparison you intend
to perform. Your code is much more maintainable and readable. Use the overloads of the methods of the System.String and
System.Array classes that take a StringComparison enumeration parameter. You specify which type of comparison to perform.
Avoid using the == and != operators when you test for equality. The String.CompareTo instance methods always perform
an ordinal case-sensitive comparison. They are primarily suited for ordering strings alphabetically.
You can intern a string or retrieve a reference to an existing interned string by calling the String.Intern method. To
determine whether a string is interned, call the String.IsInterned method.
See also
System.Globalization.CultureInfo
System.StringComparer
Strings
Comparing strings
Globalizing and localizing applications
How to safely cast by using pattern matching and the
is and as operators
9/3/2020 • 4 minutes to read • Edit Online
Because objects are polymorphic, it's possible for a variable of a base class type to hold a derived type. To access
the derived type's instance members, it's necessary to cast the value back to the derived type. However, a cast
creates the risk of throwing an InvalidCastException. C# provides pattern matching statements that perform a cast
conditionally only when it will succeed. C# also provides the is and as operators to test if a value is of a certain
type.
The following example shows how to use the pattern matching is statement:
class Animal
{
public void Eat() { Console.WriteLine("Eating."); }
public override string ToString()
{
return "I am an animal.";
}
}
class Mammal : Animal { }
class Giraffe : Mammal { }
class SuperNova { }
class Program
{
static void Main(string[] args)
{
var g = new Giraffe();
var a = new Animal();
FeedMammals(g);
FeedMammals(a);
// Output:
// Eating.
// Animal is not a Mammal
The preceding sample demonstrates a few features of pattern matching syntax. The if (a is Mammal m) statement
combines the test with an initialization assignment. The assignment occurs only when the test succeeds. The
variable m is only in scope in the embedded if statement where it has been assigned. You cannot access m later
in the same method. The preceding example also shows how to use the as operator to convert an object to a
specified type.
You can also use the same syntax for testing if a nullable value type has a value, as shown in the following example:
class Program
{
static void Main(string[] args)
{
int i = 5;
PatternMatchingNullable(i);
int? j = null;
PatternMatchingNullable(j);
double d = 9.78654;
PatternMatchingNullable(d);
PatternMatchingSwitch(i);
PatternMatchingSwitch(j);
PatternMatchingSwitch(d);
}
The preceding sample demonstrates other features of pattern matching to use with conversions. You can test a
variable for the null pattern by checking specifically for the null value. When the runtime value of the variable is
null , an is statement checking for a type always returns false . The pattern matching is statement doesn't
allow a nullable value type, such as int? or Nullable<int> , but you can test for any other value type. The is
patterns from the preceding example are not limited to the nullable value types. You can also use those patterns to
test if a variable of a reference type has a value or it's null .
The preceding sample also shows how you use the type pattern in a switch statement where the variable may be
one of many different types.
If you want to test if a variable is a given type, but not assign it to a new variable, you can use the is and as
operators for reference types and nullable value types. The following code shows how to use the is and as
statements that were part of the C# language before pattern matching was introduced to test if a variable is of a
given type:
class Animal
{
public void Eat() { Console.WriteLine("Eating."); }
public override string ToString()
{
return "I am an animal.";
}
}
class Mammal : Animal { }
class Giraffe : Mammal { }
class SuperNova { }
class Program
{
static void Main(string[] args)
{
// Use the is operator to verify the type.
// before performing a cast.
Giraffe g = new Giraffe();
UseIsOperator(g);
double d = 9.78654;
UseAsWithNullable(d);
}
As you can see by comparing this code with the pattern matching code, the pattern matching syntax provides
more robust features by combining the test and the assignment in a single statement. Use the pattern matching
syntax whenever possible.
The .NET Compiler Platform SDK
9/3/2020 • 5 minutes to read • Edit Online
Compilers build a detailed model of application code as they validate the syntax and semantics of that code. They
use this model to build the executable output from the source code. The .NET Compiler Platform SDK provides
access to this model. Increasingly, we rely on integrated development environment (IDE) features such as
IntelliSense, refactoring, intelligent rename, "Find all references," and "Go to definition" to increase our productivity.
We rely on code analysis tools to improve our code quality, and code generators to aid in application construction.
As these tools get smarter, they need access to more and more of the model that only compilers create as they
process application code. This is the core mission of the Roslyn APIs: opening up the opaque boxes and allowing
tools and end users to share in the wealth of information compilers have about our code. Instead of being opaque
source-code-in and object-code-out translators, through Roslyn, compilers become platforms: APIs that you can use
for code-related tasks in your tools and applications.
Next steps
The .NET Compiler Platform SDK includes the latest language object models for code generation, analysis, and
refactoring. This section provides a conceptual overview of the .NET Compiler Platform SDK. Further details can be
found in the quickstarts, samples, and tutorials sections.
You can learn more about the concepts in the .NET Compiler Platform SDK in these five topics:
Explore code with the syntax visualizer
Understand the compiler API model
Work with syntax
Work with semantics
Work with a workspace
To get started, you'll need to install the .NET Compiler Platform SDK :
Compilers process the code you write following structured rules that often differ from the way humans read and
understand code. A basic understanding of the model used by compilers is essential to understanding the APIs you
use when building Roslyn-based tools.
Each phase of this pipeline is a separate component. First, the parse phase tokenizes and parses source text into
syntax that follows the language grammar. Second, the declaration phase analyzes source and imported metadata
to form named symbols. Next, the bind phase matches identifiers in the code to symbols. Finally, the emit phase
emits an assembly with all the information built up by the compiler.
Corresponding to each of those phases, the .NET Compiler Platform SDK exposes an object model that allows
access to the information at that phase. The parsing phase exposes a syntax tree, the declaration phase exposes a
hierarchical symbol table, the binding phase exposes the result of the compiler's semantic analysis, and the emit
phase is an API that produces IL byte codes.
Each compiler combines these components together as a single end-to-end whole.
These APIs are the same ones used by Visual Studio. For instance, the code outlining and formatting features use
the syntax trees, the Object Browser , and navigation features use the symbol table, refactorings and Go to
Definition use the semantic model, and Edit and Continue uses all of these, including the Emit API.
API layers
The .NET compiler SDK consists of several layers of APIs: compiler APIs, diagnostic APIs, scripting APIs, and
workspaces APIs.
Compiler APIs
The compiler layer contains the object models that correspond to information exposed at each phase of the
compiler pipeline, both syntactic and semantic. The compiler layer also contains an immutable snapshot of a single
invocation of a compiler, including assembly references, compiler options, and source code files. There are two
distinct APIs that represent the C# language and the Visual Basic language. The two APIs are similar in shape but
tailored for high-fidelity to each individual language. This layer has no dependencies on Visual Studio components.
Diagnostic APIs
As part of its analysis the compiler may produce a set of diagnostics covering everything from syntax, semantic,
and definite assignment errors to various warnings and informational diagnostics. The Compiler API layer exposes
diagnostics through an extensible API that allows user-defined analyzers to be plugged into the compilation
process. It allows user-defined diagnostics, such as those produced by tools like StyleCop or FxCop, to be produced
alongside compiler-defined diagnostics. Producing diagnostics in this way has the benefit of integrating naturally
with tools such as MSBuild and Visual Studio, which depend on diagnostics for experiences such as halting a build
based on policy and showing live squiggles in the editor and suggesting code fixes.
Scripting APIs
Hosting and scripting APIs are part of the compiler layer. You can use them for executing code snippets and
accumulating a runtime execution context. The C# interactive REPL (Read-Evaluate-Print Loop) uses these APIs. The
REPL enables you to use C# as a scripting language, executing the code interactively as you write it.
Workspaces APIs
The Workspaces layer contains the Workspace API, which is the starting point for doing code analysis and
refactoring over entire solutions. It assists you in organizing all the information about the projects in a solution into
a single object model, offering you direct access to the compiler layer object models without needing to parse files,
configure options, or manage project-to-project dependencies.
In addition, the Workspaces layer surfaces a set of APIs used when implementing code analysis and refactoring
tools that function within a host environment like the Visual Studio IDE. Examples include the Find All References,
Formatting, and Code Generation APIs.
This layer has no dependencies on Visual Studio components.
Work with syntax
5/11/2020 • 8 minutes to read • Edit Online
The syntax tree is a fundamental data structure exposed by the compiler APIs. These trees represent the lexical and
syntactic structure of source code. They serve two important purposes:
To allow tools - such as an IDE, add-ins, code analysis tools, and refactorings - to see and process the syntactic
structure of source code in a user's project.
To enable tools - such as refactorings and an IDE - to create, modify, and rearrange source code in a natural
manner without having to use direct text edits. By creating and manipulating trees, tools can easily create and
rearrange source code.
Syntax trees
Syntax trees are the primary structure used for compilation, code analysis, binding, refactoring, IDE features, and
code generation. No part of the source code is understood without it first being identified and categorized into one
of many well-known structural language elements.
Syntax trees have three key attributes. The first attribute is that syntax trees hold all the source information in full
fidelity. Full fidelity means that the syntax tree contains every piece of information found in the source text, every
grammatical construct, every lexical token, and everything else in between, including white space, comments, and
preprocessor directives. For example, each literal mentioned in the source is represented exactly as it was typed.
Syntax trees also capture errors in source code when the program is incomplete or malformed by representing
skipped or missing tokens.
The second attribute of syntax trees is that they can produce the exact text that they were parsed from. From any
syntax node, it's possible to get the text representation of the subtree rooted at that node. This ability means that
syntax trees can be used as a way to construct and edit source text. By creating a tree you have, by implication,
created the equivalent text, and by editing a syntax tree, making a new tree out of changes to an existing tree, you
have effectively edited the text.
The third attribute of syntax trees is that they are immutable and thread-safe. After a tree is obtained, it's a
snapshot of the current state of the code and never changes. This allows multiple users to interact with the same
syntax tree at the same time in different threads without locking or duplication. Because the trees are immutable
and no modifications can be made directly to a tree, factory methods help create and modify syntax trees by
creating additional snapshots of the tree. The trees are efficient in the way they reuse underlying nodes, so a new
version can be rebuilt fast and with little extra memory.
A syntax tree is literally a tree data structure, where non-terminal structural elements parent other elements. Each
syntax tree is made up of nodes, tokens, and trivia.
Syntax nodes
Syntax nodes are one of the primary elements of syntax trees. These nodes represent syntactic constructs such as
declarations, statements, clauses, and expressions. Each category of syntax nodes is represented by a separate class
derived from Microsoft.CodeAnalysis.SyntaxNode. The set of node classes is not extensible.
All syntax nodes are non-terminal nodes in the syntax tree, which means they always have other nodes and tokens
as children. As a child of another node, each node has a parent node that can be accessed through the
SyntaxNode.Parent property. Because nodes and trees are immutable, the parent of a node never changes. The root
of the tree has a null parent.
Each node has a SyntaxNode.ChildNodes() method, which returns a list of child nodes in sequential order based on
their position in the source text. This list does not contain tokens. Each node also has methods to examine
Descendants, such as DescendantNodes, DescendantTokens, or DescendantTrivia - that represent a list of all the
nodes, tokens, or trivia that exist in the subtree rooted by that node.
In addition, each syntax node subclass exposes all the same children through strongly typed properties. For
example, a BinaryExpressionSyntax node class has three additional properties specific to binary operators: Left,
OperatorToken, and Right. The type of Left and Right is ExpressionSyntax, and the type of OperatorToken is
SyntaxToken.
Some syntax nodes have optional children. For example, an IfStatementSyntax has an optional ElseClauseSyntax. If
the child is not present, the property returns null.
Syntax tokens
Syntax tokens are the terminals of the language grammar, representing the smallest syntactic fragments of the
code. They are never parents of other nodes or tokens. Syntax tokens consist of keywords, identifiers, literals, and
punctuation.
For efficiency purposes, the SyntaxToken type is a CLR value type. Therefore, unlike syntax nodes, there is only one
structure for all kinds of tokens with a mix of properties that have meaning depending on the kind of token that is
being represented.
For example, an integer literal token represents a numeric value. In addition to the raw source text the token spans,
the literal token has a Value property that tells you the exact decoded integer value. This property is typed as
Object because it may be one of many primitive types.
The ValueText property tells you the same information as the Value property; however this property is always
typed as String. An identifier in C# source text may include Unicode escape characters, yet the syntax of the escape
sequence itself is not considered part of the identifier name. So although the raw text spanned by the token does
include the escape sequence, the ValueText property does not. Instead, it includes the Unicode characters identified
by the escape. For example, if the source text contains an identifier written as \u03C0 , then the ValueText property
for this token will return π .
Syntax trivia
Syntax trivia represent the parts of the source text that are largely insignificant for normal understanding of the
code, such as white space, comments, and preprocessor directives. Like syntax tokens, trivia are value types. The
single Microsoft.CodeAnalysis.SyntaxTrivia type is used to describe all kinds of trivia.
Because trivia are not part of the normal language syntax and can appear anywhere between any two tokens, they
are not included in the syntax tree as a child of a node. Yet, because they are important when implementing a
feature like refactoring and to maintain full fidelity with the source text, they do exist as part of the syntax tree.
You can access trivia by inspecting a token's SyntaxToken.LeadingTrivia or SyntaxToken.TrailingTrivia collections.
When source text is parsed, sequences of trivia are associated with tokens. In general, a token owns any trivia after
it on the same line up to the next token. Any trivia after that line is associated with the following token. The first
token in the source file gets all the initial trivia, and the last sequence of trivia in the file is tacked onto the end-of-
file token, which otherwise has zero width.
Unlike syntax nodes and tokens, syntax trivia do not have parents. Yet, because they are part of the tree and each is
associated with a single token, you may access the token it is associated with using the SyntaxTrivia.Token property.
Spans
Each node, token, or trivia knows its position within the source text and the number of characters it consists of. A
text position is represented as a 32-bit integer, which is a zero-based char index. A TextSpan object is the
beginning position and a count of characters, both represented as integers. If TextSpan has a zero length, it refers
to a location between two characters.
Each node has two TextSpan properties: Span and FullSpan.
The Span property is the text span from the start of the first token in the node's subtree to the end of the last token.
This span does not include any leading or trailing trivia.
The FullSpan property is the text span that includes the node's normal span, plus the span of any leading or trailing
trivia.
For example:
if (x > 3)
{
|| // this is bad
|throw new Exception("Not right.");| // better exception?||
}
The statement node inside the block has a span indicated by the single vertical bars (|). It includes the characters
throw new Exception("Not right."); . The full span is indicated by the double vertical bars (||). It includes the same
characters as the span and the characters associated with the leading and trailing trivia.
Kinds
Each node, token, or trivia has a SyntaxNode.RawKind property, of type System.Int32, that identifies the exact
syntax element represented. This value can be cast to a language-specific enumeration. Each language, C# or Visual
Basic, has a single SyntaxKind enumeration (Microsoft.CodeAnalysis.CSharp.SyntaxKind and
Microsoft.CodeAnalysis.VisualBasic.SyntaxKind, respectively) that lists all the possible nodes, tokens, and trivia
elements in the grammar. This conversion can be done automatically by accessing the CSharpExtensions.Kind or
VisualBasicExtensions.Kind extension methods.
The RawKind property allows for easy disambiguation of syntax node types that share the same node class. For
tokens and trivia, this property is the only way to distinguish one type of element from another.
For example, a single BinaryExpressionSyntax class has Left, OperatorToken, and Right as children. The Kind
property distinguishes whether it is an AddExpression, SubtractExpression, or MultiplyExpression kind of syntax
node.
Errors
Even when the source text contains syntax errors, a full syntax tree that is round-trippable to the source is exposed.
When the parser encounters code that does not conform to the defined syntax of the language, it uses one of two
techniques to create a syntax tree:
If the parser expects a particular kind of token but does not find it, it may insert a missing token into the
syntax tree in the location that the token was expected. A missing token represents the actual token that was
expected, but it has an empty span, and its SyntaxNode.IsMissing property returns true .
The parser may skip tokens until it finds one where it can continue parsing. In this case, the skipped tokens
are attached as a trivia node with the kind SkippedTokensTrivia.
Work with semantics
3/12/2020 • 3 minutes to read • Edit Online
Syntax trees represent the lexical and syntactic structure of source code. Although this information alone is enough
to describe all the declarations and logic in the source, it is not enough information to identify what is being
referenced. A name may represent:
a type
a field
a method
a local variable
Although each of these is uniquely different, determining which one an identifier actually refers to often requires a
deep understanding of the language rules.
There are program elements represented in source code, and programs can also refer to previously compiled
libraries, packaged in assembly files. Although no source code, and therefore no syntax nodes or trees, are
available for assemblies, programs can still refer to elements inside them.
For those tasks, you need the Semantic model .
In addition to a syntactic model of the source code, a semantic model encapsulates the language rules, giving you
an easy way to correctly match identifiers with the correct program element being referenced.
Compilation
A compilation is a representation of everything needed to compile a C# or Visual Basic program, which includes all
the assembly references, compiler options, and source files.
Because all this information is in one place, the elements contained in the source code can be described in more
detail. The compilation represents each declared type, member, or variable as a symbol. The compilation contains a
variety of methods that help you find and relate the symbols that have either been declared in the source code or
imported as metadata from an assembly.
Similar to syntax trees, compilations are immutable. After you create a compilation, it cannot be changed by you or
anyone else you might be sharing it with. However, you can create a new compilation from an existing compilation,
specifying a change as you do so. For example, you might create a compilation that is the same in every way as an
existing compilation, except it may include an additional source file or assembly reference.
Symbols
A symbol represents a distinct element declared by the source code or imported from an assembly as metadata.
Every namespace, type, method, property, field, event, parameter, or local variable is represented by a symbol.
A variety of methods and properties on the Compilation type help you find symbols. For example, you can find a
symbol for a declared type by its common metadata name. You can also access the entire symbol table as a tree of
symbols rooted by the global namespace.
Symbols also contain additional information that the compiler determines from the source or metadata, such as
other referenced symbols. Each kind of symbol is represented by a separate interface derived from ISymbol, each
with its own methods and properties detailing the information the compiler has gathered. Many of these
properties directly reference other symbols. For example, the IMethodSymbol.ReturnType property tells you the
actual type symbol that the method declaration references.
Symbols present a common representation of namespaces, types, and members, between source code and
metadata. For example, a method that was declared in source code and a method that was imported from
metadata are both represented by an IMethodSymbol with the same properties.
Symbols are similar in concept to the CLR type system as represented by the System.Reflection API, yet they are
richer in that they model more than just types. Namespaces, local variables, and labels are all symbols. In addition,
symbols are a representation of language concepts, not CLR concepts. There is a lot of overlap, but there are many
meaningful distinctions as well. For instance, an iterator method in C# or Visual Basic is a single symbol. However,
when the iterator method is translated to CLR metadata, it is a type and multiple methods.
Semantic model
A semantic model represents all the semantic information for a single source file. You can use it to discover the
following:
The symbols referenced at a specific location in source.
The resultant type of any expression.
All diagnostics, which are errors and warnings.
How variables flow in and out of regions of source.
The answers to more speculative questions.
Work with a workspace
3/12/2020 • 2 minutes to read • Edit Online
The Workspaces layer is the starting point for doing code analysis and refactoring over entire solutions. Within
this layer, the Workspace API assists you in organizing all the information about the projects in a solution into a
single object model, offering you direct access to compiler layer object models like source text, syntax trees,
semantic models, and compilations without needing to parse files, configure options, or manage inter-project
dependencies.
Host environments, like an IDE, provide a workspace for you corresponding to the open solution. It is also possible
to use this model outside of an IDE by simply loading a solution file.
Workspace
A workspace is an active representation of your solution as a collection of projects, each with a collection of
documents. A workspace is typically tied to a host environment that is constantly changing as a user types or
manipulates properties.
The Workspace provides access to the current model of the solution. When a change in the host environment
occurs, the workspace fires corresponding events, and the Workspace.CurrentSolution property is updated. For
example, when the user types in a text editor corresponding to one of the source documents, the workspace uses
an event to signal that the overall model of the solution has changed and which document was modified. You can
then react to those changes by analyzing the new model for correctness, highlighting areas of significance, or
making a suggestion for a code change.
You can also create stand-alone workspaces that are disconnected from the host environment or used in an
application that has no host environment.
This article provides an overview of the Syntax Visualizer tool that ships as part of the .NET Compiler Platform
("Roslyn") SDK. The Syntax Visualizer is a tool window that helps you inspect and explore syntax trees. It's an
essential tool to understand the models for code you want to analyze. It's also a debugging aid when you develop
your own applications using the .NET Compiler Platform (“Roslyn”) SDK. Open this tool as you create your first
analyzers. The visualizer helps you understand the models used by the APIs. You can also use tools like SharpLab or
LINQPad to inspect code and understand syntax trees.
Syntax Visualizer
The Syntax Visualizer enables inspection of the syntax tree for the C# or Visual Basic code file in the current
active editor window inside the Visual Studio IDE. The visualizer can be launched by clicking on View > Other
Windows > Syntax Visualizer . You can also use the Quick Launch toolbar in the upper right corner. Type
"syntax", and the command to open the Syntax Visualizer should appear.
This command opens the Syntax Visualizer as a floating tool window. If you don't have a code editor window open,
the display is blank, as shown in the following figure.
Dock this tool window at a convenient location inside Visual Studio, such as the left side. The Visualizer shows
information about the current code file.
Create a new project using the File > New Project command. You can create either a Visual Basic or C# project.
When Visual Studio opens the main code file for this project, the visualizer displays the syntax tree for it. You can
open any existing C# / Visual Basic file in this Visual Studio instance, and the visualizer displays that file's syntax
tree. If you have multiple code files open inside Visual Studio, the visualizer displays the syntax tree for the
currently active code file, (the code file that has keyboard focus.)
C#
Visual Basic
As shown in the preceding images, the visualizer tool window displays the syntax tree at the top and a property
grid at the bottom. The property grid displays the properties of the item that is currently selected in the tree,
including the .NET Type and the Kind (SyntaxKind) of the item.
Syntax trees comprise three types of items – nodes, tokens, and trivia. You can read more about these types in the
Work with syntax article. Items of each type are represented using a different color. Click on the ‘Legend’ button for
an overview of the colors used.
Each item in the tree also displays its own span . The span is the indices (the starting and ending position) of that
node in the text file. In the preceding C# example, the selected “UsingKeyword [0..5)” token has a Span that is five
characters wide, [0..5). The "[..)" notation means that the starting index is part of the span, but the ending index is
not.
There are two ways to navigate the tree:
Expand or click on items in the tree. The visualizer automatically selects the text corresponding to this item’s
span in the code editor.
Click or select text in the code editor. In the preceding Visual Basic example, if you select the line containing
"Module Module1" in the code editor, the visualizer automatically navigates to the corresponding
ModuleStatement node in the tree.
The visualizer highlights the item in the tree whose span best matches the span of the text selected in the editor.
The visualizer refreshes the tree to match modifications in the active code file. Add a call to Console.WriteLine()
inside Main() . As you type, the visualizer refreshes the tree.
Pause typing once you have typed Console. . The tree has some items colored in pink. At this point, there are
errors (also referred to as ‘Diagnostics’) in the typed code. These errors are attached to nodes, tokens, and trivia in
the syntax tree. The visualizer shows you which items have errors attached to them highlighting the background in
pink. You can inspect the errors on any item colored pink by hovering over the item. The visualizer only displays
syntactic errors (those errors related to the syntax of the typed code); it doesn't display any semantic errors.
Syntax Graphs
Right click on any item in the tree and click on View Directed Syntax Graph .
C#
Visual Basic
The visualizer displays a graphical representation of the subtree rooted at the selected item. Try these steps for the
MethodDeclaration node corresponding to the Main() method in the C# example. The visualizer displays a
syntax graph that looks as follows:
The syntax graph viewer has an option to display a legend for its coloring scheme. You can also hover over
individual items in the syntax graph with the mouse to view the properties corresponding to that item.
You can view syntax graphs for different items in the tree repeatedly and the graphs will always be displayed in the
same window inside Visual Studio. You can dock this window at a convenient location inside Visual Studio so that
you don’t have to switch between tabs to view a new syntax graph. The bottom, below code editor windows, is
often convenient.
Here is the docking layout to use with the visualizer tool window and the syntax graph window:
Another option is to put the syntax graph window on a second monitor, in a dual monitor setup.
Inspecting semantics
The Syntax Visualizer enables rudimentary inspection of symbols and semantic information. Type
double x = 1 + 1; inside Main() in the C# example. Then, select the expression 1 + 1 in the code editor window.
The visualizer highlights the AddExpression node in the visualizer. Right click on this AddExpression and click on
View Symbol (if any) . Notice that most of the menu items have the "if any" qualifier. The Syntax Visualizer
inspects properties of a Node, including properties that may not be present for all nodes.
The property grid in the visualizer updates as shown in the following figure: The symbol for the expression is a
SynthesizedIntrinsicOperatorSymbol with Kind = Method .
Try View TypeSymbol (if any) for the same AddExpression node. The property grid in the visualizer updates as
shown in the following figure, indicating that the type of the selected expression is Int32 .
Try View Conver ted TypeSymbol (if any) for the same AddExpression node. The property grid updates
indicating that although the type of the expression is Int32 , the converted type of the expression is Double as
shown in the following figure. This node includes converted type symbol information because the Int32
expression occurs in a context where it must be converted to a Double . This conversion satisfies the Double type
specified for the variable x on the left-hand side of the assignment operator.
Finally, try View Constant Value (if any) for the same AddExpression node. The property grid shows that the
value of the expression is a compile time constant with value 2 .
The preceding example can also be replicated in Visual Basic. Type Dim x As Double = 1 + 1 in a Visual Basic file.
Select the expression 1 + 1 in the code editor window. The visualizer highlights the corresponding
AddExpression node in the visualizer. Repeat the preceding steps for this AddExpression and you should see
identical results.
Examine more code in Visual Basic. Update your main Visual Basic file with the following code:
Imports C = System.Console
Module Program
Sub Main(args As String())
C.WriteLine()
End Sub
End Module
This code introduces an alias named C that maps to the type System.Console at the top of the file and uses this
alias inside Main() . Select the use of this alias, the C in C.WriteLine() , inside the Main() method. The visualizer
selects the corresponding IdentifierName node in the visualizer. Right-click this node and click on View Symbol
(if any) . The property grid indicates that this identifier is bound to the type System.Console as shown in the
following figure:
Try View AliasSymbol (if any) for the same IdentifierName node. The property grid indicates the identifier is
an alias with name C that is bound to the System.Console target. In other words, the property grid provides
information regarding the AliasSymbol corresponding to the identifier C .
Inspect the symbol corresponding to any declared type, method, property. Select the corresponding node in the
visualizer and click on View Symbol (if any) . Select the method Sub Main() , including the body of the method.
Click on View Symbol (if any) for the corresponding SubBlock node in the visualizer. The property grid shows
the MethodSymbol for this SubBlock has name Main with return type Void .
The above Visual Basic examples can be easily replicated in C#. Type using C = System.Console; in place of
Imports C = System.Console for the alias. The preceding steps in C# yield identical results in the visualizer window.
Semantic inspection operations are only available on nodes. They are not available on tokens or trivia. Not all
nodes have interesting semantic information to inspect. When a node doesn't have interesting semantic
information, clicking on View * Symbol (if any) shows a blank property grid.
You can read more about APIs for performing semantic analysis in the Work with semantics overview document.
Closing the syntax visualizer
You can close the visualizer window when you are not using it to examine source code. The syntax visualizer
updates its display as you navigate through code, editing and changing the source. It can get distracting when you
are not using it.
Get started with syntax analysis
3/3/2020 • 13 minutes to read • Edit Online
In this tutorial, you'll explore the Syntax API . The Syntax API provides access to the data structures that describe a
C# or Visual Basic program. These data structures have enough detail that they can fully represent any program of
any size. These structures can describe complete programs that compile and run correctly. They can also describe
incomplete programs, as you write them, in the editor.
To enable this rich expression, the data structures and APIs that make up the Syntax API are necessarily complex.
Let's start with what the data structure looks like for the typical "Hello World" program:
using System;
using System.Collections.Generic;
using System.Linq;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}
Look at the text of the previous program. You recognize familiar elements. The entire text represents a single
source file, or a compilation unit . The first three lines of that source file are using directives . The remaining
source is contained in a namespace declaration . The namespace declaration contains a child class declaration .
The class declaration contains one method declaration .
The Syntax API creates a tree structure with the root representing the compilation unit. Nodes in the tree represent
the using directives, namespace declaration and all the other elements of the program. The tree structure continues
down to the lowest levels: the string "Hello World!" is a string literal token that is a descendent of an argument .
The Syntax API provides access to the structure of the program. You can query for specific code practices, walk the
entire tree to understand the code, and create new trees by modifying the existing tree.
That brief description provides an overview of the kind of information accessible using the Syntax API. The Syntax
API is nothing more than a formal API that describes the familiar code constructs you know from C#. The full
capabilities include information about how the code is formatted including line breaks, white space, and indenting.
Using this information, you can fully represent the code as written and read by human programmers or the
compiler. Using this structure enables you to interact with the source code on a deeply meaningful level. It's no
longer text strings, but data that represents the structure of a C# program.
To get started, you'll need to install the .NET Compiler Platform SDK :
Traversing trees
You can examine the nodes in a syntax tree in two ways. You can traverse the tree to examine each node, or you can
query for specific elements or nodes.
Manual traversal
You can see the finished code for this sample in our GitHub repository.
NOTE
The Syntax Tree types use inheritance to describe the different syntax elements that are valid at different locations in the
program. Using these APIs often means casting properties or collection members to specific derived types. In the following
examples, the assignment and the casts are separate statements, using explicitly typed variables. You can read the code to
see the return types of the API and the runtime type of the objects returned. In practice, it's more common to use implicitly
typed variables and rely on API names to describe the type of objects being examined.
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(""Hello, World!"");
}
}
}";
Next, add the following code to build the syntax tree for the code text in the programText constant. Add the
following line to your Main method:
Those two lines create the tree and retrieve the root node of that tree. You can now examine the nodes in the tree.
Add these lines to your Main method to display some of the properties of the root node in the tree:
Run the application to see what your code has discovered about the root node in this tree.
Typically, you'd traverse the tree to learn about the code. In this example, you're analyzing code you know to
explore the APIs. Add the following code to examine the first member of the root node:
MemberDeclarationSyntax firstMember = root.Members[0];
WriteLine($"The first member is a {firstMember.Kind()}.");
var helloWorldDeclaration = (NamespaceDeclarationSyntax)firstMember;
The method declaration node contains all the syntactic information about the method. Let's display the return type
of the Main method, the number and types of the arguments, and the body text of the method. Add the following
code:
Run the program to see all the information you've discovered about this program:
The tree is a CompilationUnit node.
The tree has 1 elements in it.
The tree has 4 using statements. They are:
System
System.Collections
System.Linq
System.Text
The first member is a NamespaceDeclaration.
There are 1 members declared in this namespace.
The first member is a ClassDeclaration.
There are 1 members declared in the Program class.
The first member is a MethodDeclaration.
The return type of the Main method is void.
The method has 1 parameters.
The type of the args parameter is string[].
The body text of the Main method follows:
{
Console.WriteLine("Hello, World!");
}
Query methods
In addition to traversing trees, you can also explore the syntax tree using the query methods defined on
Microsoft.CodeAnalysis.SyntaxNode. These methods should be immediately familiar to anyone familiar with XPath.
You can use these methods with LINQ to quickly find things in a tree. The SyntaxNode has query methods such as
DescendantNodes, AncestorsAndSelf and ChildNodes.
You can use these query methods to find the argument to the Main method as an alternative to navigating the
tree. Add the following code to the bottom of your Main method:
WriteLine(argsParameter == argsParameter2);
The first statement uses a LINQ expression and the DescendantNodes method to locate the same parameter as in
the previous example.
Run the program, and you can see that the LINQ expression found the same parameter as manually navigating the
tree.
The sample uses WriteLine statements to display information about the syntax trees as they are traversed. You can
also learn much more by running the finished program under the debugger. You can examine more of the
properties and methods that are part of the syntax tree created for the hello world program.
Syntax walkers
Often you want to find all nodes of a specific type in a syntax tree, for example, every property declaration in a file.
By extending the Microsoft.CodeAnalysis.CSharp.CSharpSyntaxWalker class and overriding the
VisitPropertyDeclaration(PropertyDeclarationSyntax) method, you process every property declaration in a syntax
tree without knowing its structure beforehand. CSharpSyntaxWalker is a specific kind of CSharpSyntaxVisitor that
recursively visits a node and each of its children.
This example implements a CSharpSyntaxWalker that examines a syntax tree. It collects using directives it finds
that aren't importing a System namespace.
Create a new C# Stand-Alone Code Analysis Tool project; name it "SyntaxWalker ."
You can see the finished code for this sample in our GitHub repository. The sample on GitHub contains both
projects described in this tutorial.
As in the previous sample, you can define a string constant to hold the text of the program you're going to analyze:
namespace TopLevel
{
using Microsoft;
using System.ComponentModel;
namespace Child1
{
using Microsoft.Win32;
using System.Runtime.InteropServices;
class Foo { }
}
namespace Child2
{
using System.CodeDom;
using Microsoft.CSharp;
class Bar { }
}
}";
This source text contains using directives scattered across four different locations: the file-level, in the top-level
namespace, and in the two nested namespaces. This example highlights a core scenario for using the
CSharpSyntaxWalker class to query code. It would be cumbersome to visit every node in the root syntax tree to
find using declarations. Instead, you create a derived class and override the method that gets called only when the
current node in the tree is a using directive. Your visitor does not do any work on any other node types. This single
method examines each of the using statements and builds a collection of the namespaces that aren't in the
System namespace. You build a CSharpSyntaxWalker that examines all the using statements, but only the using
statements.
Now that you've defined the program text, you need to create a SyntaxTree and get the root of that tree:
Next, create a new class. In Visual Studio, choose Project > Add New Item . In the Add New Item dialog type
UsingCollector.cs as the filename.
You implement the using visitor functionality in the UsingCollector class. Start by making the UsingCollector
class derive from CSharpSyntaxWalker.
The base class, CSharpSyntaxWalker implements the logic to visit each node in the syntax tree. The derived class
overrides the methods called for the specific nodes you're interested in. In this case, you're interested in any using
directive. That means you must override the VisitUsingDirective(UsingDirectiveSyntax) method. The one argument
to this method is a Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax object. That's an important
advantage to using the visitors: they call the overridden methods with arguments already cast to the specific node
type. The Microsoft.CodeAnalysis.CSharp.Syntax.UsingDirectiveSyntax class has a Name property that stores the
name of the namespace being imported. It is a Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax. Add the
following code in the VisitUsingDirective(UsingDirectiveSyntax) override:
As with the earlier example, you've added a variety of WriteLine statements to aid in understanding of this
method. You can see when it's called, and what arguments are passed to it each time.
Finally, you need to add two lines of code to create the UsingCollector and have it visit the root node, collecting all
the using statements. Then, add a foreach loop to display all the using statements your collector found:
Compile and run the program. You should see the following output:
VisitUsingDirective called with System.
VisitUsingDirective called with System.Collections.Generic.
VisitUsingDirective called with System.Linq.
VisitUsingDirective called with System.Text.
VisitUsingDirective called with Microsoft.CodeAnalysis.
Success. Adding Microsoft.CodeAnalysis.
VisitUsingDirective called with Microsoft.CodeAnalysis.CSharp.
Success. Adding Microsoft.CodeAnalysis.CSharp.
VisitUsingDirective called with Microsoft.
Success. Adding Microsoft.
VisitUsingDirective called with System.ComponentModel.
VisitUsingDirective called with Microsoft.Win32.
Success. Adding Microsoft.Win32.
VisitUsingDirective called with System.Runtime.InteropServices.
VisitUsingDirective called with System.CodeDom.
VisitUsingDirective called with Microsoft.CSharp.
Success. Adding Microsoft.CSharp.
Microsoft.CodeAnalysis
Microsoft.CodeAnalysis.CSharp
Microsoft
Microsoft.Win32
Microsoft.CSharp
Press any key to continue . . .
Congratulations! You've used the Syntax API to locate specific kinds of C# statements and declarations in C#
source code.
Get started with semantic analysis
3/3/2020 • 8 minutes to read • Edit Online
This tutorial assumes you're familiar with the Syntax API. The get started with syntax analysis article provides
sufficient introduction.
In this tutorial, you explore the Symbol and Binding APIs . These APIs provide information about the semantic
meaning of a program. They enable you to ask and answer questions about the types represented by any symbol
in your program.
You'll need to install the .NET Compiler Platform SDK :
Querying symbols
In this tutorial, you look at the "Hello World" program again. This time, you query the symbols in the program to
understand what types those symbols represent. You query for the types in a namespace, and learn to find the
methods available on a type.
You can see the finished code for this sample in our GitHub repository.
NOTE
The Syntax Tree types use inheritance to describe the different syntax elements that are valid at different locations in the
program. Using these APIs often means casting properties or collection members to specific derived types. In the following
examples, the assignment and the casts are separate statements, using explicitly typed variables. You can read the code to
see the return types of the API and the runtime type of the objects returned. In practice, it's more common to use implicitly
typed variables and rely on API names to describe the type of objects being examined.
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(""Hello, World!"");
}
}
}";
Next, add the following code to build the syntax tree for the code text in the programText constant. Add the
following line to your Main method:
SyntaxTree tree = CSharpSyntaxTree.ParseText(programText);
Next, build a CSharpCompilation from the tree you already created. The "Hello World" sample relies on the String
and Console types. You need to reference the assembly that declares those two types in your compilation. Add the
following line to your Main method to create a compilation of your syntax tree, including the reference to the
appropriate assembly:
Binding a name
The Compilation creates the SemanticModel from the SyntaxTree. After creating the model, you can query it to find
the first using directive, and retrieve the symbol information for the System namespace. Add these two lines to
your Main method to create the semantic model and retrieve the symbol for the first using statement:
The preceding code shows how to bind the name in the first using directive to retrieve a
Microsoft.CodeAnalysis.SymbolInfo for the System namespace. The preceding code also illustrates that you use the
syntax model to find the structure of the code; you use the semantic model to understand its meaning. The
syntax model finds the string System in the using statement. The semantic model has all the information about
the types defined in the System namespace.
From the SymbolInfo object you can obtain the Microsoft.CodeAnalysis.ISymbol using the SymbolInfo.Symbol
property. This property returns the symbol this expression refers to. For expressions that don't refer to anything
(such as numeric literals) this property is null . When the SymbolInfo.Symbol is not null, the ISymbol.Kind denotes
the type of the symbol. In this example, the ISymbol.Kind property is a SymbolKind.Namespace. Add the following
code to your Main method. It retrieves the symbol for the System namespace and then displays all the child
namespaces declared in the System namespace:
var systemSymbol = (INamespaceSymbol)nameInfo.Symbol;
foreach (INamespaceSymbol ns in systemSymbol.GetNamespaceMembers())
{
Console.WriteLine(ns);
}
Run the program and you should see the following output:
System.Collections
System.Configuration
System.Deployment
System.Diagnostics
System.Globalization
System.IO
System.Numerics
System.Reflection
System.Resources
System.Runtime
System.Security
System.StubHelpers
System.Text
System.Threading
Press any key to continue . . .
NOTE
The output does not include every namespace that is a child namespace of the System namespace. It displays every
namespace that is present in this compilation, which only references the assembly where System.String is declared. Any
namespaces declared in other assemblies are not known to this compilation
Binding an expression
The preceding code shows how to find a symbol by binding to a name. There are other expressions in a C#
program that can be bound that aren't names. To demonstrate this capability, let's access the binding to a simple
string literal.
The "Hello World" program contains a Microsoft.CodeAnalysis.CSharp.Syntax.LiteralExpressionSyntax, the "Hello,
World!" string displayed to the console.
You find the "Hello, World!" string by locating the single string literal in the program. Then, once you've located the
syntax node, get the type info for that node from the semantic model. Add the following code to your Main
method:
The Microsoft.CodeAnalysis.TypeInfo struct includes a TypeInfo.Type property that enables access to the semantic
information about the type of the literal. In this example, that's the string type. Add a declaration that assigns this
property to a local variable:
That source sequence contains all members, including properties and fields, so filter it using the
ImmutableArray<T>.OfType method to find elements that are Microsoft.CodeAnalysis.IMethodSymbol objects:
Next, add another filter to return only those methods that are public and return a string :
Select only the name property, and only distinct names by removing any overloads:
You can also build the full query using the LINQ query syntax, and then display all the method names in the
console:
Build and run the program. You should see the following output:
Join
Substring
Trim
TrimStart
TrimEnd
Normalize
PadLeft
PadRight
ToLower
ToLowerInvariant
ToUpper
ToUpperInvariant
ToString
Insert
Replace
Remove
Format
Copy
Concat
Intern
IsInterned
Press any key to continue . . .
You've used the Semantic API to find and display information about the symbols that are part of this program.
Get started with syntax transformation
9/3/2020 • 12 minutes to read • Edit Online
This tutorial builds on concepts and techniques explored in the Get started with syntax analysis and Get started
with semantic analysis quickstarts. If you haven't already, you should complete those quickstarts before beginning
this one.
In this quickstart, you explore techniques for creating and transforming syntax trees. In combination with the
techniques you learned in previous quickstarts, you create your first command-line refactoring!
You'll create name syntax nodes to build the tree that represents the using System.Collections.Generic;
statement. NameSyntax is the base class for four types of names that appear in C#. You compose these four types
of names together to create any name that can appear in the C# language:
Microsoft.CodeAnalysis.CSharp.Syntax.NameSyntax, which represents simple single identifier names like
System and Microsoft .
Microsoft.CodeAnalysis.CSharp.Syntax.GenericNameSyntax, which represents a generic type or method name
such as List<int> .
Microsoft.CodeAnalysis.CSharp.Syntax.QualifiedNameSyntax, which represents a qualified name of the form
<left-name>.<right-identifier-or-generic-name> such as System.IO .
Microsoft.CodeAnalysis.CSharp.Syntax.AliasQualifiedNameSyntax, which represents a name using an assembly
extern alias such a LibraryV2::Foo .
You use the IdentifierName(String) method to create a NameSyntax node. Add the following code in your Main
method in Program.cs :
The preceding code creates an IdentifierNameSyntax object and assigns it to the variable name . Many of the Roslyn
APIs return base classes to make it easier to work with related types. The variable name , an NameSyntax, can be
reused as you build the QualifiedNameSyntax. Don't use type inference as you build the sample. You'll automate
that step in this project.
You've created the name. Now, it's time to build more nodes into the tree by building a QualifiedNameSyntax. The
new tree uses name as the left of the name, and a new IdentifierNameSyntax for the Collections namespace as
the right side of the QualifiedNameSyntax. Add the following code to program.cs :
Run the code again, and see the results. You're building a tree of nodes that represents code. You'll continue this
pattern to build the QualifiedNameSyntax for the namespace System.Collections.Generic . Add the following code
to Program.cs :
Run the program again to see that you've built the tree for the code to add.
Create a modified tree
You've built a small syntax tree that contains one statement. The APIs to create new nodes are the right choice to
create single statements or other small code blocks. However, to build larger blocks of code, you should use
methods that replace nodes or insert nodes into an existing tree. Remember that syntax trees are immutable. The
Syntax API doesn't provide any mechanism for modifying an existing syntax tree after construction. Instead, it
provides methods that produce new trees based on changes to existing ones. With* methods are defined in
concrete classes that derive from SyntaxNode or in extension methods declared in the SyntaxNodeExtensions class.
These methods create a new node by applying changes to an existing node's child properties. Additionally, the
ReplaceNode extension method can be used to replace a descendent node in a subtree. This method also updates
the parent to point to the newly created child and repeats this process up the entire tree - a process known as re-
spinning the tree.
The next step is to create a tree that represents an entire (small) program and then modify it. Add the following
code to the beginning of the Program class:
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(""Hello, World!"");
}
}
}";
NOTE
The example code uses the System.Collections namespace and not the System.Collections.Generic namespace.
Next, add the following code to the bottom of the Main method to parse the text and create a tree:
Run the program and look carefully at the output. The newusing hasn't been placed in the root tree. The original
tree hasn't been changed.
Add the following code using the ReplaceNode extension method to create a new tree. The new tree is the result of
replacing the existing import with the updated newUsing node. You assign this new tree to the existing root
variable:
Run the program again. This time the tree now correctly imports the System.Collections.Generic namespace.
Transform trees using SyntaxRewriters
The With* and ReplaceNode methods provide convenient means to transform individual branches of a syntax tree.
The Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter class performs multiple transformations on a syntax
tree. The Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter class is a subclass of
Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult>. The CSharpSyntaxRewriter applies a transformation
to a specific type of SyntaxNode. You can apply transformations to multiple types of SyntaxNode objects wherever
they appear in a syntax tree. The second project in this quickstart creates a command-line refactoring that removes
explicit types in local variable declarations anywhere that type inference could be used.
Create a new C# Stand-Alone Code Analysis Tool project. In Visual Studio, right-click the
SyntaxTransformationQuickStart solution node. Choose Add > New Project to display the New Project dialog .
Under Visual C# > Extensibility , choose Stand-Alone Code Analysis Tool . Name your project
TransformationCS and click OK.
The first step is to create a class that derives from CSharpSyntaxRewriter to perform your transformations. Add a
new class file to the project. In Visual Studio, choose Project > Add Class.... In the Add New Item dialog type
TypeInferenceRewriter.cs as the filename.
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
Add the following code to declare a private read-only field to hold a SemanticModel and initialize it in the
constructor. You will need this field later on to determine where type inference can be used:
private readonly SemanticModel SemanticModel;
NOTE
Many of the Roslyn APIs declare return types that are base classes of the actual runtime types returned. In many scenarios,
one kind of node may be replaced by another kind of node entirely - or even removed. In this example, the
VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax) method returns a SyntaxNode, instead of the derived type
of LocalDeclarationStatementSyntax. This rewriter returns a new LocalDeclarationStatementSyntax node based on the existing
one.
This quickstart handles local variable declarations. You could extend it to other declarations such as foreach loops,
for loops, LINQ expressions, and lambda expressions. Furthermore this rewriter will only transform declarations
of the simplest form:
If you want to explore on your own, consider extending the finished sample for these types of variable declarations:
Add the following code to the body of the VisitLocalDeclarationStatement method to skip rewriting these forms of
declarations:
if (node.Declaration.Variables.Count > 1)
{
return node;
}
if (node.Declaration.Variables[0].Initializer == null)
{
return node;
}
The method indicates that no rewriting takes place by returning the node parameter unmodified. If neither of those
if expressions are true, the node represents a possible declaration with initialization. Add these statements to
extract the type name specified in the declaration and bind it using the SemanticModel field to obtain a type
symbol:
var declarator = node.Declaration.Variables.First();
var variableTypeName = node.Declaration.Type;
Finally, add the following if statement to replace the existing type name with the var keyword if the type of the
initializer expression matches the type specified:
if (SymbolEqualityComparer.Default.Equals(variableType, initializerInfo.Type))
{
TypeSyntax varTypeName = SyntaxFactory.IdentifierName("var")
.WithLeadingTrivia(variableTypeName.GetLeadingTrivia())
.WithTrailingTrivia(variableTypeName.GetTrailingTrivia());
The conditional is required because the declaration may cast the initializer expression to a base class or interface. If
that's desired, the types on the left and right-hand side of the assignment don't match. Removing the explicit type in
these cases would change the semantics of a program. var is specified as an identifier rather than a keyword
because var is a contextual keyword. The leading and trailing trivia (white space) are transferred from the old type
name to the var keyword to maintain vertical white space and indentation. It's simpler to use ReplaceNode rather
than With* to transform the LocalDeclarationStatementSyntax because the type name is actually the grandchild of
the declaration statement.
You've finished the TypeInferenceRewriter . Now return to your Program.cs file to finish the example. Create a test
Compilation and obtain the SemanticModel from it. Use that SemanticModel to try your TypeInferenceRewriter .
You'll do this step last. In the meantime declare a placeholder variable representing your test compilation:
After pausing a moment, you should see an error squiggle appear reporting that no CreateTestCompilation
method exists. Press Ctrl+Period to open the light-bulb and then press Enter to invoke the Generate Method
Stub command. This command will generate a method stub for the CreateTestCompilation method in the Program
class. You'll come back to fill in this method later:
Write the following code to iterate over each SyntaxTree in the test Compilation. For each one, initialize a new
TypeInferenceRewriter with the SemanticModel for that tree:
if (newSource != sourceTree.GetRoot())
{
File.WriteAllText(sourceTree.FilePath, newSource.ToFullString());
}
}
Inside the foreach statement you created, add the following code to perform the transformation on each source
tree. This code conditionally writes out the new transformed tree if any edits were made. Your rewriter should only
modify a tree if it encounters one or more local variable declarations that could be simplified using type inference:
if (newSource != sourceTree.GetRoot())
{
File.WriteAllText(sourceTree.FilePath, newSource.ToFullString());
}
You should see squiggles under the File.WriteAllText code. Select the light bulb, and add the necessary
using System.IO; statement.
You're almost done! There's one step left: creating a test Compilation. Since you haven't been using type inference at
all during this quickstart, it would have made a perfect test case. Unfortunately, creating a Compilation from a C#
project file is beyond the scope of this walkthrough. But fortunately, if you've been following instructions carefully,
there's hope. Replace the contents of the CreateTestCompilation method with the following code. It creates a test
compilation that coincidentally matches the project described in this quickstart:
String programPath = @"..\..\..\Program.cs";
String programText = File.ReadAllText(programPath);
SyntaxTree programTree =
CSharpSyntaxTree.ParseText(programText)
.WithFilePath(programPath);
MetadataReference mscorlib =
MetadataReference.CreateFromFile(typeof(object).Assembly.Location);
MetadataReference codeAnalysis =
MetadataReference.CreateFromFile(typeof(SyntaxTree).Assembly.Location);
MetadataReference csharpCodeAnalysis =
MetadataReference.CreateFromFile(typeof(CSharpSyntaxTree).Assembly.Location);
return CSharpCompilation.Create("TransformationCS",
sourceTrees,
references,
new CSharpCompilationOptions(OutputKind.ConsoleApplication));
Cross your fingers and run the project. In Visual Studio, choose Debug > Star t Debugging . You should be
prompted by Visual Studio that the files in your project have changed. Click "Yes to All " to reload the modified
files. Examine them to observe your awesomeness. Note how much cleaner the code looks without all those explicit
and redundant type specifiers.
Congratulations! You've used the Compiler APIs to write your own refactoring that searches all files in a C#
project for certain syntactic patterns, analyzes the semantics of source code that matches those patterns, and
transforms it. You're now officially a refactoring author!
Tutorial: Write your first analyzer and code fix
9/3/2020 • 26 minutes to read • Edit Online
The .NET Compiler Platform SDK provides the tools you need to create custom warnings that target C# or Visual
Basic code. Your analyzer contains code that recognizes violations of your rule. Your code fix contains the code
that fixes the violation. The rules you implement can be anything from code structure to coding style to naming
conventions and more. The .NET Compiler Platform provides the framework for running analysis as developers are
writing code, and all the Visual Studio UI features for fixing code: showing squiggles in the editor, populating the
Visual Studio Error List, creating the "light bulb" suggestions and showing the rich preview of the suggested fixes.
In this tutorial, you'll explore the creation of an analyzer and an accompanying code fix using the Roslyn APIs. An
analyzer is a way to perform source code analysis and report a problem to the user. Optionally, an analyzer can also
provide a code fix that represents a modification to the user's source code. This tutorial creates an analyzer that
finds local variable declarations that could be declared using the const modifier but are not. The accompanying
code fix modifies those declarations to add the const modifier.
Prerequisites
NOTE
The current Visual Studio Analyzer with code fix (.NET Standard) template has a known bug in it and should be fixed in
Visual Studio 2019 version 16.7. The projects in the template will not compile unless the following changes are made:
1. Select Tools > Options > NuGet Package Manager > Package Sources
Select the plus button, to add a new source:
Set the Source to https://dotnet.myget.org/F/roslyn-analyzers/api/v3/index.json and select Update
2. From the Solution Explorer , right-click on the MakeConst.Vsix project, and select Edit Project File
Update the <AssemblyName> node to add the .Visx suffix:
<AssemblyName>MakeConst.Vsix</AssemblyName>
Update the <ProjectReference> node on line 41 to alter the TargetFramework value:
<ProjectReference Update="@(ProjectReference)"
AdditionalProperties="TargetFramework=netstandard2.0" />
3. Update the MakeConstUnitTests.cs file, in the MakeConst.Test project:
Change line 9 to the following, notice namespace alteration:
using Verify = Microsoft.CodeAnalysis.CSharp.Testing.MSTest.CodeFixVerifier<
Change line 24 to the following method:
await Verify.VerifyAnalyzerAsync(test);
Change line 62 to the following method:
await Verify.VerifyCodeFixAsync(test, expected, fixtest);
int x = 0;
Console.WriteLine(x);
In the code above, x is assigned a constant value and is never modified. It can be declared using the const
modifier:
const int x = 0;
Console.WriteLine(x);
The analysis to determine whether a variable can be made constant is involved, requiring syntactic analysis,
constant analysis of the initializer expression and dataflow analysis to ensure that the variable is never written to.
The .NET Compiler Platform provides APIs that make it easier to perform this analysis. The first step is to create a
new C# Analyzer with code fix project.
In Visual Studio, choose File > New > Project... to display the New Project dialog.
Under Visual C# > Extensibility , choose Analyzer with code fix (.NET Standard) .
Name your project "MakeConst " and click OK.
The analyzer with code fix template creates three projects: one contains the analyzer and code fix, the second is a
unit test project, and the third is the VSIX project. The default startup project is the VSIX project. Press F5 to start
the VSIX project. This starts a second instance of Visual Studio that has loaded your new analyzer.
TIP
When you run your analyzer, you start a second copy of Visual Studio. This second copy uses a different registry hive to store
settings. That enables you to differentiate the visual settings in the two copies of Visual Studio. You can pick a different theme
for the experimental run of Visual Studio. In addition, don't roam your settings or login to your Visual Studio account using
the experimental run of Visual Studio. That keeps the settings different.
In the second Visual Studio instance that you just started, create a new C# Console Application project (either .NET
Core or .NET Framework project will work -- analyzers work at the source level.) Hover over the token with a wavy
underline, and the warning text provided by an analyzer appears.
The template creates an analyzer that reports a warning on each type declaration where the type name contains
lowercase letters, as shown in the following figure:
The template also provides a code fix that changes any type name containing lower case characters to all upper
case. You can click on the light bulb displayed with the warning to see the suggested changes. Accepting the
suggested changes updates the type name and all references to that type in the solution. Now that you've seen the
initial analyzer in action, close the second Visual Studio instance and return to your analyzer project.
You don't have to start a second copy of Visual Studio and create new code to test every change in your analyzer.
The template also creates a unit test project for you. That project contains two tests. TestMethod1 shows the typical
format of a test that analyzes code without triggering a diagnostic. TestMethod2 shows the format of a test that
triggers a diagnostic, and then applies a suggested code fix. As you build your analyzer and code fix, you'll write
tests for different code structures to verify your work. Unit tests for analyzers are much quicker than testing them
interactively with Visual Studio.
TIP
Analyzer unit tests are a great tool when you know what code constructs should and shouldn't trigger your analyzer. Loading
your analyzer in another copy of Visual Studio is a great tool to explore and find constructs you may not have thought about
yet.
Also, change the Access Modifier drop-down to public . That makes it easier to use these constants in unit tests.
When you have finished, the resource editor should appear as follow figure shows:
The remaining changes are in the analyzer file. Open MakeConstAnalyzer.cs in Visual Studio. Change the
registered action from one that acts on symbols to one that acts on syntax. In the
MakeConstAnalyzerAnalyzer.Initialize method, find the line that registers the action on symbols:
context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.NamedType);
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.LocalDeclarationStatement);
After that change, you can delete the AnalyzeSymbol method. This analyzer examines
SyntaxKind.LocalDeclarationStatement, not SymbolKind.NamedType statements. Notice that AnalyzeNode has red
squiggles under it. The code you just added references an AnalyzeNode method that hasn't been declared. Declare
that method using the following code:
int x = 0;
Console.WriteLine(x);
The first step is to find local declarations. Add the following code to AnalyzeNode in MakeConstAnalyzer.cs :
This cast always succeeds because your analyzer registered for changes to local declarations, and only local
declarations. No other node type triggers a call to your AnalyzeNode method. Next, check the declaration for any
const modifiers. If you find them, return immediately. The following code looks for any const modifiers on the
local declaration:
Finally, you need to check that the variable could be const . That means making sure it is never assigned after it is
initialized.
You'll perform some semantic analysis using the SyntaxNodeAnalysisContext. You use the context argument to
determine whether the local variable declaration can be made const . A Microsoft.CodeAnalysis.SemanticModel
represents all of semantic information in a single source file. You can learn more in the article that covers semantic
models. You'll use the Microsoft.CodeAnalysis.SemanticModel to perform data flow analysis on the local declaration
statement. Then, you use the results of this data flow analysis to ensure that the local variable isn't written with a
new value anywhere else. Call the GetDeclaredSymbol extension method to retrieve the ILocalSymbol for the
variable and check that it isn't contained with the DataFlowAnalysis.WrittenOutside collection of the data flow
analysis. Add the following code to the end of the AnalyzeNode method:
// Retrieve the local symbol for each variable in the local declaration
// and ensure that it is not written outside of the data flow analysis region.
var variable = localDeclaration.Declaration.Variables.Single();
var variableSymbol = context.SemanticModel.GetDeclaredSymbol(variable);
if (dataFlowAnalysis.WrittenOutside.Contains(variableSymbol))
{
return;
}
The code just added ensures that the variable isn't modified, and can therefore be made const . It's time to raise the
diagnostic. Add the following code as the last line in AnalyzeNode :
context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.GetLocation()));
You can check your progress by pressing F5 to run your analyzer. You can load the console application you created
earlier and then add the following test code:
int x = 0;
Console.WriteLine(x);
The light bulb should appear, and your analyzer should report a diagnostic. However, the light bulb still uses the
template generated code fix, and tells you it can be made upper case. The next section explains how to write the
code fix.
const int x = 0;
Console.WriteLine(x);
The user chooses it from the light bulb UI in the editor and Visual Studio changes the code.
Open the MakeConstCodeFixProvider.cs file added by the template. This code fix is already wired up to the
Diagnostic ID produced by your diagnostic analyzer, but it doesn't yet implement the right code transform. First you
should remove some of the template code. Change the title string to "Make constant":
var declaration =
root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType<LocalDeclarationStatementSyntax>
().First();
Next, change the last line to register a code fix. Your fix will create a new document that results from adding the
const modifier to an existing declaration:
You'll notice red squiggles in the code you just added on the symbol MakeConstAsync . Add a declaration for
MakeConstAsync like the following code:
private async Task<Document> MakeConstAsync(Document document,
LocalDeclarationStatementSyntax localDeclaration,
CancellationToken cancellationToken)
{
}
Your new MakeConstAsync method will transform the Document representing the user's source file into a new
Document that now contains a const declaration.
You create a new const keyword token to insert at the front of the declaration statement. Be careful to first remove
any leading trivia from the first token of the declaration statement and attach it to the const token. Add the
following code to the MakeConstAsync method:
Next, add the const token to the declaration using the following code:
// Insert the const token into the modifiers list, creating a new modifiers list.
var newModifiers = trimmedLocal.Modifiers.Insert(0, constToken);
// Produce the new local declaration.
var newLocal = trimmedLocal
.WithModifiers(newModifiers)
.WithDeclaration(localDeclaration.Declaration);
Next, format the new declaration to match C# formatting rules. Formatting your changes to match existing code
creates a better experience. Add the following statement immediately after the existing code:
A new namespace is required for this code. Add the following using directive to the top of the file:
using Microsoft.CodeAnalysis.Formatting;
The final step is to make your edit. There are three steps to this process:
1. Get a handle to the existing document.
2. Create a new document by replacing the existing declaration with the new declaration.
3. Return the new document.
Add the following code to the end of the MakeConstAsync method:
// Replace the old local declaration with the new local declaration.
var oldRoot = await document.GetSyntaxRootAsync(cancellationToken);
var newRoot = oldRoot.ReplaceNode(localDeclaration, formattedLocal);
Your code fix is ready to try. Press F5 to run the analyzer project in a second instance of Visual Studio. In the second
Visual Studio instance, create a new C# Console Application project and add a few local variable declarations
initialized with constant values to the Main method. You'll see that they are reported as warnings as below.
You've made a lot of progress. There are squiggles under the declarations that can be made const . But there is still
work to do. This works fine if you add const to the declarations starting with i , then j and finally k . But, if you
add the const modifier in a different order, starting with k , your analyzer creates errors: k can't be declared
const , unless i and j are both already const . You've got to do more analysis to ensure you handle the
different ways variables can be declared and initialized.
[DataTestMethod]
[DataRow("")]
public void WhenTestCodeIsValidNoDiagnosticIsTriggered(string testCode)
{
VerifyCSharpDiagnostic(testCode);
}
You can create a new data row for this test by defining any code fragment that should not cause your diagnostic to
trigger a warning. This overload of VerifyCSharpDiagnostic passes when there are no diagnostics triggered for the
source code fragment.
Next, replace TestMethod2 with this test that ensures a diagnostic is raised and a code fix applied for the source
code fragment:
[DataTestMethod]
[DataRow(LocalIntCouldBeConstant, LocalIntCouldBeConstantFixed, 10, 13)]
public void WhenDiagnosticIsRaisedFixUpdatesCode(
string test,
string fixTest,
int line,
int column)
{
var expected = new DiagnosticResult
{
Id = MakeConstAnalyzer.DiagnosticId,
Message = new LocalizableResourceString(nameof(MakeConst.Resources.AnalyzerMessageFormat),
MakeConst.Resources.ResourceManager, typeof(MakeConst.Resources)).ToString(),
Severity = DiagnosticSeverity.Warning,
Locations =
new[] {
new DiagnosticResultLocation("Test0.cs", line, column)
}
};
VerifyCSharpDiagnostic(test, expected);
VerifyCSharpFix(test, fixTest);
}
The preceding code also made a couple changes to the code that builds the expected diagnostic result. It uses the
public constants registered in the MakeConst analyzer. In addition, it uses two string constants for the input and
fixed source. Add the following string constants to the UnitTest class:
namespace MakeConstTest
{
class Program
{
static void Main(string[] args)
{
int i = 0;
Console.WriteLine(i);
}
}
}";
namespace MakeConstTest
{
class Program
{
static void Main(string[] args)
{
const int i = 0;
Console.WriteLine(i);
}
}
}";
Run these two tests to make sure they pass. In Visual Studio, open the Test Explorer by selecting Test > Windows
> Test Explorer . Then select the Run All link.
Create tests for valid declarations
As a general rule, analyzers should exit as quickly as possible, doing minimal work. Visual Studio calls registered
analyzers as the user edits code. Responsiveness is a key requirement. There are several test cases for code that
should not raise your diagnostic. Your analyzer already handles one of those tests, the case where a variable is
assigned after being initialized. Add the following string constant to your tests to represent that case:
namespace MakeConstTest
{
class Program
{
static void Main(string[] args)
{
int i = 0;
Console.WriteLine(i++);
}
}
}";
Then, add a data row for this test as shown in the snippet below:
[DataTestMethod]
[DataRow(""),
DataRow(VariableAssigned)]
public void WhenTestCodeIsValidNoDiagnosticIsTriggered(string testCode)
This test passes as well. Next, add constants for conditions you haven't handled yet:
Declarations that are already const , because they are already const:
namespace MakeConstTest
{
class Program
{
static void Main(string[] args)
{
const int i = 0;
Console.WriteLine(i);
}
}
}";
namespace MakeConstTest
{
class Program
{
static void Main(string[] args)
{
int i;
i = 0;
Console.WriteLine(i);
}
}
}";
Declarations where the initializer is not a constant, because they can't be compile-time constants:
namespace MakeConstTest
{
class Program
{
static void Main(string[] args)
{
int i = DateTime.Now.DayOfYear;
Console.WriteLine(i);
}
}
}";
It can be even more complicated because C# allows multiple declarations as one statement. Consider the following
test case string constant:
namespace MakeConstTest
{
class Program
{
static void Main(string[] args)
{
int i = 0, j = DateTime.Now.DayOfYear;
Console.WriteLine(i, j);
}
}
}";
The variable i can be made constant, but the variable j cannot. Therefore, this statement cannot be made a
const declaration. Add the DataRow declarations for all these tests:
[DataTestMethod]
[DataRow(""),
DataRow(VariableAssigned),
DataRow(AlreadyConst),
DataRow(NoInitializer),
DataRow(InitializerNotConstant),
DataRow(MultipleInitializers)]
public void WhenTestCodeIsValidNoDiagnosticIsTriggered(string testCode)
Run your tests again, and you'll see these new test cases fail.
// Retrieve the local symbol for each variable in the local declaration
// and ensure that it is not written outside of the data flow analysis region.
var variable = localDeclaration.Declaration.Variables.Single();
var variableSymbol = context.SemanticModel.GetDeclaredSymbol(variable);
if (dataFlowAnalysis.WrittenOutside.Contains(variableSymbol))
{
return;
}
The first foreach loop examines each variable declaration using syntactic analysis. The first check guarantees that
the variable has an initializer. The second check guarantees that the initializer is a constant. The second loop has the
original semantic analysis. The semantic checks are in a separate loop because it has a greater impact on
performance. Run your tests again, and you should see them all pass.
namespace MakeConstTest
{
class Program
{
static void Main(string[] args)
{
int x = ""abc"";
}
}
}";
In addition, reference types are not handled properly. The only constant value allowed for a reference type is null ,
except in this case of System.String, which allows string literals. In other words, const string s = "abc" is legal, but
const object s = "abc" is not. This code snippet verifies that condition:
namespace MakeConstTest
{
class Program
{
static void Main(string[] args)
{
object s = ""abc"";
}
}
}";
To be thorough, you need to add another test to make sure that you can create a constant declaration for a string.
The following snippet defines both the code that raises the diagnostic, and the code after the fix has been applied:
namespace MakeConstTest
{
class Program
{
static void Main(string[] args)
{
string s = ""abc"";
}
}
}";
namespace MakeConstTest
{
class Program
{
static void Main(string[] args)
{
const string s = ""abc"";
}
}
}";
Finally, if a variable is declared with the var keyword, the code fix does the wrong thing and generates a
const var declaration, which is not supported by the C# language. To fix this bug, the code fix must replace the
var keyword with the inferred type's name:
private const string DeclarationUsesVar = @"
using System;
namespace MakeConstTest
{
class Program
{
static void Main(string[] args)
{
var item = 4;
}
}
}";
namespace MakeConstTest
{
class Program
{
static void Main(string[] args)
{
const int item = 4;
}
}
}";
private const string StringDeclarationUsesVar = @"
using System;
namespace MakeConstTest
{
class Program
{
static void Main(string[] args)
{
var item = ""abc"";
}
}
}";
private const string StringDeclarationUsesVarFixedHasType = @"
using System;
namespace MakeConstTest
{
class Program
{
static void Main(string[] args)
{
const string item = ""abc"";
}
}
}";
These changes update the data row declarations for both tests. The following code shows these tests with all data
row attributes:
//No diagnostics expected to show up
[DataTestMethod]
[DataRow(""),
DataRow(VariableAssigned),
DataRow(AlreadyConst),
DataRow(NoInitializer),
DataRow(InitializerNotConstant),
DataRow(MultipleInitializers),
DataRow(DeclarationIsInvalid),
DataRow(ReferenceTypeIsntString)]
public void WhenTestCodeIsValidNoDiagnosticIsTriggered(string testCode)
{
VerifyCSharpDiagnostic(testCode);
}
[DataTestMethod]
[DataRow(LocalIntCouldBeConstant, LocalIntCouldBeConstantFixed, 10, 13),
DataRow(ConstantIsString, ConstantIsStringFixed, 10, 13),
DataRow(DeclarationUsesVar, DeclarationUsesVarFixedHasType, 10, 13),
DataRow(StringDeclarationUsesVar, StringDeclarationUsesVarFixedHasType, 10, 13)]
public void WhenDiagosticIsRaisedFixUpdatesCode(
string test,
string fixTest,
int line,
int column)
{
var expected = new DiagnosticResult
{
Id = MakeConstAnalyzer.DiagnosticId,
Message = new LocalizableResourceString(nameof(MakeConst.Resources.AnalyzerMessageFormat),
MakeConst.Resources.ResourceManager, typeof(MakeConst.Resources)).ToString(),
Severity = DiagnosticSeverity.Warning,
Locations =
new[] {
new DiagnosticResultLocation("Test0.cs", line, column)
}
};
VerifyCSharpDiagnostic(test, expected);
VerifyCSharpFix(test, fixTest);
}
Fortunately, all of the above bugs can be addressed using the same techniques that you just learned.
To fix the first bug, first open DiagnosticAnalyzer.cs and locate the foreach loop where each of the local
declaration's initializers are checked to ensure that they're assigned with constant values. Immediately before the
first foreach loop, call context.SemanticModel.GetTypeInfo() to retrieve detailed information about the declared type
of the local declaration:
Then, inside your foreach loop, check each initializer to make sure it's convertible to the variable type. Add the
following check after ensuring that the initializer is a constant:
// Ensure that the initializer value can be converted to the type of the
// local declaration without a user-defined conversion.
var conversion = context.SemanticModel.ClassifyConversion(initializer.Value, variableType);
if (!conversion.Exists || conversion.IsUserDefined)
{
return;
}
The next change builds upon the last one. Before the closing curly brace of the first foreach loop, add the following
code to check the type of the local declaration when the constant is a string or null.
// Special cases:
// * If the constant value is a string, the type of the local declaration
// must be System.String.
// * If the constant value is null, the type of the local declaration must
// be a reference type.
if (constantValue.Value is string)
{
if (variableType.SpecialType != SpecialType.System_String)
{
return;
}
}
else if (variableType.IsReferenceType && constantValue.Value != null)
{
return;
}
You must write a bit more code in your code fix provider to replace the var keyword with the correct type name.
Return to CodeFixProvider.cs . The code you'll add does the following steps:
Check if the declaration is a var declaration, and if it is:
Create a new type for the inferred type.
Make sure the type declaration is not an alias. If so, it is legal to declare const var .
Make sure that var isn't a type name in this program. (If so, const var is legal).
Simplify the full type name
That sounds like a lot of code. It's not. Replace the line that declares and initializes newLocal with the following
code. It goes immediately after the initialization of newModifiers :
// If the type of the declaration is 'var', create a new type name
// for the inferred type.
var variableDeclaration = localDeclaration.Declaration;
var variableTypeName = variableDeclaration.Type;
if (variableTypeName.IsVar)
{
var semanticModel = await document.GetSemanticModelAsync(cancellationToken);
// Special case: Ensure that 'var' isn't actually an alias to another type
// (e.g. using var = System.String).
var aliasInfo = semanticModel.GetAliasInfo(variableTypeName);
if (aliasInfo == null)
{
// Retrieve the type inferred for var.
var type = semanticModel.GetTypeInfo(variableTypeName).ConvertedType;
// Special case: Ensure that 'var' isn't actually a type named 'var'.
if (type.Name != "var")
{
// Create a new TypeSyntax for the inferred type. Be careful
// to keep any leading and trailing trivia from the var keyword.
var typeName = SyntaxFactory.ParseTypeName(type.ToDisplayString())
.WithLeadingTrivia(variableTypeName.GetLeadingTrivia())
.WithTrailingTrivia(variableTypeName.GetTrailingTrivia());
You'll need to add one using directive to use the Simplifier type:
using Microsoft.CodeAnalysis.Simplification;
Run your tests, and they should all pass. Congratulate yourself by running your finished analyzer. Press Ctrl+F5 to
run the analyzer project in a second instance of Visual Studio with the Roslyn Preview extension loaded.
In the second Visual Studio instance, create a new C# Console Application project and add int x = "abc"; to
the Main method. Thanks to the first bug fix, no warning should be reported for this local variable declaration
(though there's a compiler error as expected).
Next, add object s = "abc"; to the Main method. Because of the second bug fix, no warning should be
reported.
Finally, add another local variable that uses the var keyword. You'll see that a warning is reported and a
suggestion appears beneath to the left.
Move the editor caret over the squiggly underline and press Ctrl+.. to display the suggested code fix. Upon
selecting your code fix, note that the var keyword is now handled correctly.
int i = 2;
int j = 32;
int k = i + j;
After these changes, you get red squiggles only on the first two variables. Add const to both i and j , and you
get a new warning on k because it can now be const .
Congratulations! You've created your first .NET Compiler Platform extension that performs on-the-fly code analysis
to detect an issue and provides a quick fix to correct it. Along the way, you've learned many of the code APIs that
are part of the .NET Compiler Platform SDK (Roslyn APIs). You can check your work against the completed sample
in our samples GitHub repository.
Other resources
Get started with syntax analysis
Get started with semantic analysis
C# programming guide
9/3/2020 • 2 minutes to read • Edit Online
Program sections
Inside a C# Program
Main() and Command-Line Arguments
Language Sections
Statements, Expressions, and Operators
Types
Classes and Structs
Interfaces
Delegates
Arrays
Strings
Properties
Indexers
Events
Generics
Iterators
LINQ Query Expressions
Namespaces
Unsafe Code and Pointers
XML Documentation Comments
Platform Sections
Application Domains
Assemblies in .NET
Attributes
Collections
Exceptions and Exception Handling
File System and the Registry (C# Programming Guide)
Interoperability
Reflection
See also
C# Reference
Inside a C# program
9/3/2020 • 2 minutes to read • Edit Online
The section discusses the general structure of a C# program, and includes the standard "Hello, World!" example.
In this section
Hello World -- Your First Program
General Structure of a C# Program
Identifier names
C# Coding Conventions
Related sections
Getting Started with C#
C# Programming Guide
C# Reference
Samples and tutorials
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for C#
syntax and usage.
See also
C# Programming Guide
Hello World -- Your first program
9/3/2020 • 4 minutes to read • Edit Online
In this article, you'll use Visual Studio to create the traditional "Hello World!" program. Visual Studio is a
professional Integrated Development Environment (IDE) with many features designed for .NET development. You'll
use only a few of the features in Visual Studio to create this program. To learn more about Visual Studio, see
Getting Started with Visual C#.
NOTE
Your computer might show different names or locations for some of the Visual Studio user interface elements in the following
instructions. The Visual Studio edition that you have and the settings that you use determine these elements. For more
information, see Personalizing the IDE.
Select Create a new project in the lower right corner of the image. Visual Studio displays the New Project
dialog:
NOTE
If this is the first time you've started Visual Studio, the Recent project templates list is empty.
On the new project dialog, choose "Console App (.NET Core)" and then press Next . Give your project a name, such
as "HelloWorld", then press Create .
Visual Studio opens your project. It's already a basic "Hello World!" example. Press Ctrl + F5 to run your project.
Visual Studio builds your project, converting the source code into an executable. Then, it launches a command
window that runs your new application. You should see the following text in the window:
Hello World!
Elements of a C# program
Let's examine the important parts of this program. The first line contains a comment. The characters // convert
the rest of the line to a comment.
You can also comment out a block of text by enclosing it between the /* and */ characters. This is shown in the
following example.
/* A "Hello World!" program in C#.
This program displays the string "Hello World!" on the screen. */
A C# console application must contain a Main method, in which control starts and ends. The Main method is
where you create objects and execute other methods.
The Main method is a static method that resides inside a class or a struct. In the previous "Hello World!" example,
it resides in a class named Hello . You can declare the Main method in one of the following ways:
It can return void . That means your program doesn't return a value.
It can also return an integer. The integer is the exit code for your application.
-or-
The parameter of the Main method, args , is a string array that contains the command-line arguments used to
invoke the program.
For more information about how to use command-line arguments, see the examples in Main() and Command-Line
Arguments.
Console.WriteLine("Hello World!");
See also
C# Programming Guide
Samples and tutorials
Main() and Command-Line Arguments
Getting Started with Visual C#
General Structure of a C# Program (C# Programming
Guide)
9/3/2020 • 2 minutes to read • Edit Online
C# programs can consist of one or more files. Each file can contain zero or more namespaces. A namespace can
contain types such as classes, structs, interfaces, enumerations, and delegates, in addition to other namespaces. The
following is the skeleton of a C# program that contains all of these elements.
// A skeleton of a C# program
using System;
namespace YourNamespace
{
class YourClass
{
}
struct YourStruct
{
}
interface IYourInterface
{
}
enum YourEnum
{
}
namespace YourNestedNamespace
{
struct YourStruct
{
}
}
class YourMainClass
{
static void Main(string[] args)
{
//Your program starts here...
}
}
}
Related Sections
For more information:
Classes
Structs
Namespaces
Interfaces
Delegates
C# Language Specification
For more information, see Basic concepts in the C# Language Specification. The language specification is the
definitive source for C# syntax and usage.
See also
C# Programming Guide
Inside a C# Program
C# Reference
Identifier names
2/26/2020 • 2 minutes to read • Edit Online
An identifier is the name you assign to a type (class, interface, struct, delegate, or enum), member, variable, or
namespace. Valid identifiers must follow these rules:
Identifiers must start with a letter, or _ .
Identifiers may contain Unicode letter characters, decimal digit characters, Unicode connecting characters,
Unicode combining characters, or Unicode formatting characters. For more information on Unicode
categories, see the Unicode Category Database. You can declare identifiers that match C# keywords by using
the @ prefix on the identifier. The @ is not part of the identifier name. For example, @if declares an
identifier named if . These verbatim identifiers are primarily for interoperability with identifiers declared in
other languages.
For a complete definition of valid identifiers, see the Identifiers topic in the C# Language Specification.
Naming conventions
In addition to the rules, there are a number of identifier naming conventions used throughout the .NET APIs. By
convention, C# programs use PascalCase for type names, namespaces, and all public members. In addition, the
following conventions are common:
Interface names start with a capital I .
Attribute types end with the word Attribute .
Enum types use a singular noun for non-flags, and a plural noun for flags.
Identifiers should not contain two consecutive _ characters. Those names are reserved for compiler
generated identifiers.
C# Language Specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Programming Guide
Inside a C# Program
C# Reference
Classes
Structure types
Namespaces
Interfaces
Delegates
C# Coding Conventions (C# Programming Guide)
9/3/2020 • 8 minutes to read • Edit Online
Naming Conventions
In short examples that do not include using directives, use namespace qualifications. If you know that a
namespace is imported by default in a project, you do not have to fully qualify the names from that
namespace. Qualified names can be broken after a dot (.) if they are too long for a single line, as shown in
the following example.
You do not have to change the names of objects that were created by using the Visual Studio designer tools
to make them fit other guidelines.
Layout Conventions
Good layout uses formatting to emphasize the structure of your code and to make the code easier to read.
Microsoft examples and samples conform to the following conventions:
Use the default Code Editor settings (smart indenting, four-character indents, tabs saved as spaces). For
more information, see Options, Text Editor, C#, Formatting.
Write only one statement per line.
Write only one declaration per line.
If continuation lines are not indented automatically, indent them one tab stop (four spaces).
Add at least one blank line between method definitions and property definitions.
Use parentheses to make clauses in an expression apparent, as shown in the following code.
Commenting Conventions
Place the comment on a separate line, not at the end of a line of code.
Begin comment text with an uppercase letter.
End comment text with a period.
Insert one space between the comment delimiter (//) and the comment text, as shown in the following
example.
Language Guidelines
The following sections describe practices that the C# team follows to prepare code examples and samples.
String Data Type
Use string interpolation to concatenate short strings, as shown in the following code.
To append strings in loops, especially when you are working with large amounts of text, use a StringBuilder
object.
// When the type of a variable is clear from the context, use var
// in the declaration.
var var1 = "This is clearly a string.";
var var2 = 27;
Do not use var when the type is not apparent from the right side of the assignment.
// When the type of a variable is not clear from the context, use an
// explicit type. You generally don't assume the type clear from a method name.
// A variable type is considered clear if it's a new operator or an explicit cast.
int var3 = Convert.ToInt32(Console.ReadLine());
int var4 = ExampleClass.ResultSoFar();
Do not rely on the variable name to specify the type of the variable. It might not be correct.
// Naming the following variable inputInt is misleading.
// It is a string.
var inputInt = Console.ReadLine();
Console.WriteLine(inputInt);
Do not use implicit typing to determine the type of the loop variable in foreach loops.
The following example uses explicit typing in a foreach statement.
NOTE
Be careful not to accidentally change a type of an element of the iterable collection. For example, it is easy to switch
from System.Linq.IQueryable to System.Collections.IEnumerable in a foreach statement, which changes the
execution of a query.
// Preferred syntax. Note that you cannot use var here instead of string[].
string[] vowels1 = { "a", "e", "i", "o", "u" };
// If you specify an array size, you must initialize the elements one at a time.
var vowels3 = new string[5];
vowels3[0] = "a";
vowels3[1] = "e";
// And so on.
Delegates
Use the concise syntax to create instances of a delegate type.
// First, in class Program, define the delegate type and a method that
// has a matching signature.
Simplify your code by using the C# using statement. If you have a try-finally statement in which the only
code in the finally block is a call to the Dispose method, use a using statement instead.
// This try-finally statement only calls Dispose in the finally block.
Font font1 = new Font("Arial", 10.0f);
try
{
byte charset = font1.GdiCharSet;
}
finally
{
if (font1 != null)
{
((IDisposable)font1).Dispose();
}
}
New Operator
Use the concise form of object instantiation, with implicit typing, as shown in the following declaration.
Event Handling
If you are defining an event handler that you do not need to remove later, use a lambda expression.
public Form2()
{
// You can use a lambda expression to define an event handler.
this.Click += (s, e) =>
{
MessageBox.Show(
((MouseEventArgs)e).Location.ToString());
};
}
Static Members
Call static members by using the class name: ClassName.StaticMember. This practice makes code more readable by
making static access clear. Do not qualify a static member defined in a base class with the name of a derived class.
While that code compiles, the code readability is misleading, and the code may break in the future if you add a
static member with the same name to the derived class.
LINQ Queries
Use meaningful names for query variables. The following example uses seattleCustomers for customers
who are located in Seattle.
Use aliases to make sure that property names of anonymous types are correctly capitalized, using Pascal
casing.
var localDistributors =
from customer in customers
join distributor in distributors on customer.City equals distributor.City
select new { Customer = customer, Distributor = distributor };
Rename properties when the property names in the result would be ambiguous. For example, if your query
returns a customer name and a distributor ID, instead of leaving them as Name and ID in the result,
rename them to clarify that Name is the name of a customer, and ID is the ID of a distributor.
var localDistributors2 =
from customer in customers
join distributor in distributors on customer.City equals distributor.City
select new { CustomerName = customer.Name, DistributorID = distributor.ID };
Use implicit typing in the declaration of query variables and range variables.
Align query clauses under the from clause, as shown in the previous examples.
Use where clauses before other query clauses to ensure that later query clauses operate on the reduced,
filtered set of data.
Use multiple from clauses instead of a join clause to access inner collections. For example, a collection of
Student objects might each contain a collection of test scores. When the following query is executed, it
returns each score that is over 90, along with the last name of the student who received the score.
// Use a compound from to access the inner sequence within each element.
var scoreQuery = from student in students
from score in student.Scores
where score > 90
select new { Last = student.LastName, score };
Security
Follow the guidelines in Secure Coding Guidelines.
See also
Visual Basic Coding Conventions
Secure Coding Guidelines
Main() and command-line arguments (C#
Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
The Main method is the entry point of a C# application. (Libraries and services do not require a Main method
as an entry point.) When the application is started, the Main method is the first method that is invoked.
There can only be one entry point in a C# program. If you have more than one class that has a Main method,
you must compile your program with the -main compiler option to specify which Main method to use as the
entry point. For more information, see -main (C# Compiler Options).
class TestClass
{
static void Main(string[] args)
{
// Display the number of command line arguments.
Console.WriteLine(args.Length);
}
}
Overview
The Main method is the entry point of an executable program; it is where the program control starts and
ends.
Main is declared inside a class or struct. Main must be static and it need not be public. (In the earlier
example, it receives the default access of private.) The enclosing class or struct is not required to be static.
Main can either have a void , int , or, starting with C# 7.1, Task , or Task<int> return type.
If and only if Main returns a Task or Task<int> , the declaration of Main may include the async modifier.
Note that this specifically excludes an async void Main method.
The Main method can be declared with or without a string[] parameter that contains command-line
arguments. When using Visual Studio to create Windows applications, you can add the parameter manually
or else use the GetCommandLineArgs() method to obtain the command-line arguments. Parameters are read
as zero-indexed command-line arguments. Unlike C and C++, the name of the program is not treated as the
first command-line argument in the args array, but it is the first element of the GetCommandLineArgs()
method.
The following is a list of valid Main signatures:
The preceding examples all use the public accessor modifier. That is typical, but not required.
The addition of async and Task , Task<int> return types simplifies program code when console applications
need to start and await asynchronous operations in Main .
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
Command-line Building With csc.exe
C# Programming Guide
Methods
Inside a C# Program
Command-Line Arguments (C# Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
You can send arguments to the Main method by defining the method in one of the following ways:
NOTE
To enable command-line arguments in the Main method in a Windows Forms application, you must manually modify the
signature of Main in program.cs. The code generated by the Windows Forms designer creates a Main without an input
parameter. You can also use Environment.CommandLine or Environment.GetCommandLineArgs to access the command-line
arguments from any point in a console or Windows application.
The parameter of the Main method is a String array that represents the command-line arguments. Usually you
determine whether arguments exist by testing the Length property, for example:
if (args.Length == 0)
{
System.Console.WriteLine("Please enter a numeric argument.");
return 1;
}
TIP
The args array cannot be null. So, it's safe to access the Length property without null checking.
You can also convert the string arguments to numeric types by using the Convert class or the Parse method. For
example, the following statement converts the string to a long number by using the Parse method:
You can also use the Convert class method ToInt64 to do the same thing:
Example
The following example shows how to use command-line arguments in a console application. The application takes
one argument at run time, converts the argument to an integer, and calculates the factorial of the number. If no
arguments are supplied, the application issues a message that explains the correct usage of the program.
To compile and run the application from a command prompt, follow these steps:
1. Paste the following code into any text editor, and then save the file as a text file with the name Factorial.cs.
// Add a using directive for System if the directive isn't already present.
class MainClass
{
static int Main(string[] args)
{
// Test if input arguments were supplied.
if (args.Length == 0)
{
Console.WriteLine("Please enter a numeric argument.");
Console.WriteLine("Usage: Factorial <num>");
return 1;
}
// Calculate factorial.
long result = Functions.Factorial(num);
// Print result.
if (result == -1)
Console.WriteLine("Input must be >= 0 and <= 20.");
else
Console.WriteLine($"The Factorial of {num} is {result}.");
return 0;
}
}
// If 3 is entered on command line, the
// output reads: The factorial of 3 is 6.
2. From the Star t screen or Star t menu, open a Visual Studio Developer Command Prompt window, and
then navigate to the folder that contains the file that you just created.
3. Enter the following command to compile the application.
csc Factorial.cs
If your application has no compilation errors, an executable file that's named Factorial.exe is created.
4. Enter the following command to calculate the factorial of 3:
Factorial 3
NOTE
When running an application in Visual Studio, you can specify command-line arguments in the Debug Page, Project Designer.
See also
System.Environment
C# Programming Guide
Main() and Command-Line Arguments
How to display command line arguments
Main() Return Values
Classes
How to display command-line arguments (C#
Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
Arguments provided to an executable on the command line are accessible through an optional parameter to Main
. The arguments are provided in the form of an array of strings. Each element of the array contains one argument.
White-space between arguments is removed. For example, consider these command-line invocations of a fictitious
executable:
executable.exe a b c "a"
"b"
"c"
"two"
"three"
NOTE
When you are running an application in Visual Studio, you can specify command-line arguments in the Debug Page, Project
Designer.
Example
This example displays the command-line arguments passed to a command-line application. The output shown is
for the first entry in the table above.
class CommandLine
{
static void Main(string[] args)
{
// The Length property provides the number of array elements.
Console.WriteLine($"parameter count = {args.Length}");
See also
C# Programming Guide
Command-line Building With csc.exe
Main() and Command-Line Arguments
Main() Return Values
Main() return values (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
If the return value from Main is not used, returning void allows for slightly simpler code. However, returning an
integer enables the program to communicate status information to other programs or scripts that invoke the
executable file. The return value from Main is treated as the exit code for the process. If void is returned from
Main , the exit code will be implicitly 0 . The following example shows how the return value from Main can be
accessed.
Example
This example uses .NET Core command-line tools. If you are unfamiliar with .NET Core command-line tools, you
can learn about them in this get-started article.
Modify the Main method in program.cs as follows:
When a program is executed in Windows, any value returned from the Main function is stored in an environment
variable. This environment variable can be retrieved using ERRORLEVEL from a batch file, or $LastExitCode from
powershell.
You can build the application using the dotnet CLI dotnet build command.
Next, create a Powershell script to run the application and display the result. Paste the following code into a text file
and save it as test.ps1 in the folder that contains the project. Run the powershell script by typing test.ps1 at the
powershell prompt.
Because the code returns zero, the batch file will report success. However, if you change MainReturnValTest.cs to
return a non-zero value and then recompile the program, subsequent execution of the powershell script will report
failure.
dotnet run
if ($LastExitCode -eq 0) {
Write-Host "Execution succeeded"
} else
{
Write-Host "Execution Failed"
}
Write-Host "Return value = " $LastExitCode
Sample output
Execution succeeded
Return value = 0
The advantage of the new syntax is that the compiler always generates the correct code.
Compiler-generated code
When the application entry point returns a Task or Task<int> , the compiler generates a new entry point that
calls the entry point method declared in the application code. Assuming that this entry point is called
$GeneratedMain , the compiler generates the following code for these entry points:
NOTE
If the examples used async modifier on the Main method, the compiler would generate the same code.
See also
C# Programming Guide
C# Reference
Main() and Command-Line Arguments
How to display command line arguments
Programming Concepts (C#)
9/3/2020 • 2 minutes to read • Edit Online
In This Section
T IT L E DESC RIP T IO N
Asynchronous Programming with async and await (C#) Describes how to write asynchronous solutions by using the
async and await keywords in C#. Includes a walkthrough.
Covariance and Contravariance (C#) Shows how to enable implicit conversion of generic type
parameters in interfaces and delegates.
Expression Trees (C#) Explains how you can use expression trees to enable dynamic
modification of executable code.
Iterators (C#) Describes iterators, which are used to step through collections
and return elements one at a time.
Language-Integrated Query (LINQ) (C#) Discusses the powerful query capabilities in the language
syntax of C#, and the model for querying relational databases,
XML documents, datasets, and in-memory collections.
Serialization (C#) Describes key concepts in binary, XML, and SOAP serialization.
Related Sections
Performance Tips Discusses several basic rules that may help you increase the
performance of your application.
Asynchronous programming with async and await
9/3/2020 • 13 minutes to read • Edit Online
The Task asynchronous programming model (TAP) provides an abstraction over asynchronous code. You write
code as a sequence of statements, just like always. You can read that code as though each statement completes
before the next begins. The compiler performs a number of transformations because some of those statements
may start work and return a Task that represents the ongoing work.
That's the goal of this syntax: enable code that reads like a sequence of statements, but executes in a much more
complicated order based on external resource allocation and when tasks complete. It's analogous to how people
give instructions for processes that include asynchronous tasks. Throughout this article, you'll use an example of
instructions for making a breakfast to see how the async and await keywords make it easier to reason about
code, that includes a series of asynchronous instructions. You'd write the instructions something like the
following list to explain how to make a breakfast:
1. Pour a cup of coffee.
2. Heat up a pan, then fry two eggs.
3. Fry three slices of bacon.
4. Toast two pieces of bread.
5. Add butter and jam to the toast.
6. Pour a glass of orange juice.
If you have experience with cooking, you'd execute those instructions asynchronously . You'd start warming the
pan for eggs, then start the bacon. You'd put the bread in the toaster, then start the eggs. At each step of the
process, you'd start a task, then turn your attention to tasks that are ready for your attention.
Cooking breakfast is a good example of asynchronous work that isn't parallel. One person (or thread) can handle
all these tasks. Continuing the breakfast analogy, one person can make breakfast asynchronously by starting the
next task before the first completes. The cooking progresses whether or not someone is watching it. As soon as
you start warming the pan for the eggs, you can begin frying the bacon. Once the bacon starts, you can put the
bread into the toaster.
For a parallel algorithm, you'd need multiple cooks (or threads). One would make the eggs, one the bacon, and
so on. Each one would be focused on just that one task. Each cook (or thread) would be blocked synchronously
waiting for bacon to be ready to flip, or the toast to pop.
Now, consider those same instructions written as C# statements:
using System;
using System.Threading.Tasks;
namespace AsyncBreakfast
{
class Program
{
static void Main(string[] args)
{
Coffee cup = PourCoffee();
Console.WriteLine("coffee is ready");
Juice oj = PourOJ();
Console.WriteLine("oj is ready");
Console.WriteLine("Breakfast is ready!");
}
The synchronously prepared breakfast, took roughly 30 minutes because the total is the sum of each individual
task.
NOTE
The Coffee , Egg , Bacon , Toast , and Juice classes are empty. They are simply marker classes for the purpose of
demonstration, contain no properties, and serve no other purpose.
Computers don't interpret those instructions the same way people do. The computer will block on each
statement until the work is complete before moving on to the next statement. That creates an unsatisfying
breakfast. The later tasks wouldn't be started until the earlier tasks had completed. It would take much longer to
create the breakfast, and some items would have gotten cold before being served.
If you want the computer to execute the above instructions asynchronously, you must write asynchronous code.
These concerns are important for the programs you write today. When you write client programs, you want the
UI to be responsive to user input. Your application shouldn't make a phone appear frozen while it's downloading
data from the web. When you write server programs, you don't want threads blocked. Those threads could be
serving other requests. Using synchronous code when asynchronous alternatives exist hurts your ability to scale
out less expensively. You pay for those blocked threads.
Successful modern applications require asynchronous code. Without language support, writing asynchronous
code required callbacks, completion events, or other means that obscured the original intent of the code. The
advantage of the synchronous code is that it's step-by-step actions make it easy to scan and understand.
Traditional asynchronous models forced you to focus on the asynchronous nature of the code, not on the
fundamental actions of the code.
Juice oj = PourOJ();
Console.WriteLine("oj is ready");
Console.WriteLine("Breakfast is ready!");
}
IMPORTANT
The total elapsed time is roughly the same as the initial synchonous version. The code has yet to take advantage of some
of the key features of asynchronous programming.
TIP
The method bodies of the FryEggsAsync , FryBaconAsync , and ToastBreadAsync have all been updated to return
Task<Egg> , Task<Bacon> , and Task<Toast> respectively. The methods are renamed from their original version to
include the "Async" suffix. Their implementations are shown as part of the final version later in this article.
This code doesn't block while the eggs or the bacon are cooking. This code won't start any other tasks though.
You'd still put the toast in the toaster and stare at it until it pops. But at least, you'd respond to anyone that
wanted your attention. In a restaurant where multiple orders are placed, the cook could start another breakfast
while the first is cooking.
Now, the thread working on the breakfast isn't blocked while awaiting any started task that hasn't yet finished.
For some applications, this change is all that's needed. A GUI application still responds to the user with just this
change. However, for this scenario, you want more. You don't want each of the component tasks to be executed
sequentially. It's better to start each of the component tasks before awaiting the previous task's completion.
Juice oj = PourOJ();
Console.WriteLine("oj is ready");
Console.WriteLine("Breakfast is ready!");
Next, you can move the await statements for the bacon and eggs to the end of the method, before serving
breakfast:
Console.WriteLine("Breakfast is ready!");
The asynchronously prepared breakfast took roughly 20 minutes, this is because some tasks were able to run
concurrently.
The preceding code works better. You start all the asynchronous tasks at once. You await each task only when you
need the results. The preceding code may be similar to code in a web application that makes requests of different
microservices, then combines the results into a single page. You'll make all the requests immediately, then await
all those tasks and compose the web page.
IMPORTANT
The composition of an asynchronous operation followed by synchronous work is an asynchronous operation. Stated
another way, if any portion of an operation is asynchronous, the entire operation is asynchronous.
The preceding code showed you that you can use Task or Task<TResult> objects to hold running tasks. You
await each task before using its result. The next step is to create methods that represent the combination of
other work. Before serving breakfast, you want to await the task that represents toasting the bread before
adding butter and jam. You can represent that work with the following code:
return toast;
}
The preceding method has the async modifier in its signature. That signals to the compiler that this method
contains an await statement; it contains asynchronous operations. This method represents the task that toasts
the bread, then adds butter and jam. This method returns a Task<TResult> that represents the composition of
those three operations. The main block of code now becomes:
Juice oj = PourOJ();
Console.WriteLine("oj is ready");
Console.WriteLine("Breakfast is ready!");
}
The previous change illustrated an important technique for working with asynchronous code. You compose tasks
by separating the operations into a new method that returns a task. You can choose when to await that task. You
can start other tasks concurrently.
Another option is to use WhenAny, which returns a Task<Task> that completes when any of its arguments
completes. You can await the returned task, knowing that it has already finished. The following code shows how
you could use WhenAny to await the first task to finish and then process its result. After processing the result
from the completed task, you remove that completed task from the list of tasks passed to WhenAny .
var breakfastTasks = new List<Task> { eggsTask, baconTask, toastTask };
while (breakfastTasks.Count > 0)
{
Task finishedTask = await Task.WhenAny(breakfastTasks);
if (finishedTask == eggsTask)
{
Console.WriteLine("eggs are ready");
}
else if (finishedTask == baconTask)
{
Console.WriteLine("bacon is ready");
}
else if (finishedTask == toastTask)
{
Console.WriteLine("toast is ready");
}
breakfastTasks.Remove(finishedTask);
}
After all those changes, the final version of the code looks like this:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace AsyncBreakfast
{
class Program
{
static async Task Main(string[] args)
{
Coffee cup = PourCoffee();
Console.WriteLine("coffee is ready");
Juice oj = PourOJ();
Console.WriteLine("oj is ready");
Console.WriteLine("Breakfast is ready!");
}
return toast;
}
Next steps
Learn about the task asynchronous programming model
Task asynchronous programming model
9/3/2020 • 13 minutes to read • Edit Online
You can avoid performance bottlenecks and enhance the overall responsiveness of your application by using
asynchronous programming. However, traditional techniques for writing asynchronous applications can be
complicated, making them difficult to write, debug, and maintain.
C# 5 introduced a simplified approach, async programming, that leverages asynchronous support in the .NET
Framework 4.5 and higher, .NET Core, and the Windows Runtime. The compiler does the difficult work that the
developer used to do, and your application retains a logical structure that resembles synchronous code. As a result,
you get all the advantages of asynchronous programming with a fraction of the effort.
This topic provides an overview of when and how to use async programming and includes links to support topics
that contain details and examples.
W IN DO W S RUN T IM E T Y P ES W IT H
A P P L IC AT IO N A REA . N ET T Y P ES W IT H A SY N C M ET H O DS A SY N C M ET H O DS
Asynchrony proves especially valuable for applications that access the UI thread because all UI-related activity
usually shares one thread. If any process is blocked in a synchronous application, all are blocked. Your application
stops responding, and you might conclude that it has failed when instead it's just waiting.
When you use asynchronous methods, the application continues to respond to the UI. You can resize or minimize a
window, for example, or you can close the application if you don't want to wait for it to finish.
The async-based approach adds the equivalent of an automatic transmission to the list of options that you can
choose from when designing asynchronous operations. That is, you get all the benefits of traditional asynchronous
programming but with much less effort from the developer.
Task<string> getStringTask =
client.GetStringAsync("https://docs.microsoft.com/dotnet");
DoIndependentWork();
return contents.Length;
}
void DoIndependentWork()
{
Console.WriteLine("Working...");
}
You can learn several practices from the preceding sample. Start with the method signature. It includes the async
modifier. The return type is Task<int> (See "Return Types" section for more options). The method name ends in
Async . In the body of the method, GetStringAsync returns a Task<string> . That means that when you await the
task you'll get a string ( contents ). Before awaiting the task, you can do work that doesn't rely on the string
from GetStringAsync .
Pay close attention to the await operator. It suspends GetUrlContentLengthAsync :
GetUrlContentLengthAsync can't continue until getStringTask is complete.
Meanwhile, control returns to the caller of GetUrlContentLengthAsync .
Control resumes here when getStringTask is complete.
The await operator then retrieves the string result from getStringTask .
The return statement specifies an integer result. Any methods that are awaiting GetUrlContentLengthAsync retrieve
the length value.
If GetUrlContentLengthAsync doesn't have any work that it can do between calling GetStringAsync and awaiting its
completion, you can simplify your code by calling and awaiting in the following single statement.
The following characteristics summarize what makes the previous example an async method:
The method signature includes an async modifier.
The name of an async method, by convention, ends with an "Async" suffix.
The return type is one of the following types:
Task<TResult> if your method has a return statement in which the operand has type TResult .
Task if your method has no return statement or has a return statement with no operand.
void if you're writing an async event handler.
Any other type that has a GetAwaiter method (starting with C# 7.0).
For more information, see the Return types and parameters section.
The method usually includes at least one await expression, which marks a point where the method can't
continue until the awaited asynchronous operation is complete. In the meantime, the method is suspended,
and control returns to the method's caller. The next section of this topic illustrates what happens at the
suspension point.
In async methods, you use the provided keywords and types to indicate what you want to do, and the compiler
does the rest, including keeping track of what must happen when control returns to an await point in a suspended
method. Some routine processes, such as loops and exception handling, can be difficult to handle in traditional
asynchronous code. In an async method, you write these elements much as you would in a synchronous solution,
and the problem is solved.
For more information about asynchrony in previous versions of .NET Framework, see TPL and traditional .NET
Framework asynchronous programming.
The numbers in the diagram correspond to the following steps, initiated when a calling method calls the async
method.
1. A calling method calls and awaits the GetUrlContentLengthAsync async method.
2. GetUrlContentLengthAsynccreates an HttpClient instance and calls the GetStringAsync asynchronous
method to download the contents of a website as a string.
3. Something happens in GetStringAsync that suspends its progress. Perhaps it must wait for a website to
download or some other blocking activity. To avoid blocking resources, GetStringAsync yields control to its
caller, GetUrlContentLengthAsync .
GetStringAsync returns a Task<TResult>, where TResult is a string, and GetUrlContentLengthAsync assigns
the task to the getStringTask variable. The task represents the ongoing process for the call to
GetStringAsync , with a commitment to produce an actual string value when the work is complete.
4. Because getStringTask hasn't been awaited yet, GetUrlContentLengthAsync can continue with other work
that doesn't depend on the final result from GetStringAsync . That work is represented by a call to the
synchronous method DoIndependentWork .
5. DoIndependentWork is a synchronous method that does its work and returns to its caller.
6. GetUrlContentLengthAsync has run out of work that it can do without a result from getStringTask .
GetUrlContentLengthAsync next wants to calculate and return the length of the downloaded string, but the
method can't calculate that value until the method has the string.
Therefore, GetUrlContentLengthAsync uses an await operator to suspend its progress and to yield control to
the method that called GetUrlContentLengthAsync . GetUrlContentLengthAsync returns a Task<int> to the
caller. The task represents a promise to produce an integer result that's the length of the downloaded string.
NOTE
If GetStringAsync (and therefore getStringTask ) completes before GetUrlContentLengthAsync awaits it,
control remains in GetUrlContentLengthAsync . The expense of suspending and then returning to
GetUrlContentLengthAsync would be wasted if the called asynchronous process getStringTask has already
completed and GetUrlContentLengthAsync doesn't have to wait for the final result.
Inside the calling method the processing pattern continues. The caller might do other work that doesn't
depend on the result from GetUrlContentLengthAsync before awaiting that result, or the caller might await
immediately. The calling method is waiting for GetUrlContentLengthAsync , and GetUrlContentLengthAsync is
waiting for GetStringAsync .
7. GetStringAsync completes and produces a string result. The string result isn't returned by the call to
GetStringAsync in the way that you might expect. (Remember that the method already returned a task in
step 3.) Instead, the string result is stored in the task that represents the completion of the method,
getStringTask . The await operator retrieves the result from getStringTask . The assignment statement
assigns the retrieved result to contents .
8. When GetUrlContentLengthAsync has the string result, the method can calculate the length of the string.
Then the work of GetUrlContentLengthAsync is also complete, and the waiting event handler can resume. In
the full example at the end of the topic, you can confirm that the event handler retrieves and prints the value
of the length result. If you are new to asynchronous programming, take a minute to consider the difference
between synchronous and asynchronous behavior. A synchronous method returns when its work is
complete (step 5), but an async method returns a task value when its work is suspended (steps 3 and 6).
When the async method eventually completes its work, the task is marked as completed and the result, if
any, is stored in the task.
API async methods
You might be wondering where to find methods such as GetStringAsync that support async programming. .NET
Framework 4.5 or higher and .NET Core contain many members that work with async and await . You can
recognize them by the "Async" suffix that's appended to the member name, and by their return type of Task or
Task<TResult>. For example, the System.IO.Stream class contains methods such as CopyToAsync, ReadAsync, and
WriteAsync alongside the synchronous methods CopyTo, Read, and Write.
The Windows Runtime also contains many methods that you can use with async and await in Windows apps.
For more information, see Threading and async programming for UWP development, and Asynchronous
programming (Windows Store apps) and Quickstart: Calling asynchronous APIs in C# or Visual Basic if you use
earlier versions of the Windows Runtime.
Threads
Async methods are intended to be non-blocking operations. An await expression in an async method doesn't
block the current thread while the awaited task is running. Instead, the expression signs up the rest of the method
as a continuation and returns control to the caller of the async method.
The async and await keywords don't cause additional threads to be created. Async methods don't require
multithreading because an async method doesn't run on its own thread. The method runs on the current
synchronization context and uses time on the thread only when the method is active. You can use Task.Run to
move CPU-bound work to a background thread, but a background thread doesn't help with a process that's just
waiting for results to become available.
The async-based approach to asynchronous programming is preferable to existing approaches in almost every
case. In particular, this approach is better than the BackgroundWorker class for I/O-bound operations because the
code is simpler and you don't have to guard against race conditions. In combination with the Task.Run method,
async programming is better than BackgroundWorker for CPU-bound operations because async programming
separates the coordination details of running your code from the work that Task.Run transfers to the thread pool.
The marked async method can itself be awaited by methods that call it.
An async method typically contains one or more occurrences of an await operator, but the absence of await
expressions doesn't cause a compiler error. If an async method doesn't use an await operator to mark a
suspension point, the method executes as a synchronous method does, despite the async modifier. The compiler
issues a warning for such methods.
async and await are contextual keywords. For more information and examples, see the following topics:
async
await
Return types and parameters
An async method typically returns a Task or a Task<TResult>. Inside an async method, an await operator is
applied to a task that's returned from a call to another async method.
You specify Task<TResult> as the return type if the method contains a return statement that specifies an operand
of type TResult .
You use Task as the return type if the method has no return statement or has a return statement that doesn't return
an operand.
Starting with C# 7.0, you can also specify any other return type, provided that the type includes a GetAwaiter
method. ValueTask<TResult> is an example of such a type. It is available in the System.Threading.Tasks.Extension
NuGet package.
The following example shows how you declare and call a method that returns a Task<TResult> or a Task:
return hours;
}
Each returned task represents ongoing work. A task encapsulates information about the state of the asynchronous
process and, eventually, either the final result from the process or the exception that the process raises if it doesn't
succeed.
An async method can also have a void return type. This return type is used primarily to define event handlers,
where a void return type is required. Async event handlers often serve as the starting point for async programs.
An async method that has a void return type can't be awaited, and the caller of a void-returning method can't
catch any exceptions that the method throws.
An async method can't declare in, ref or out parameters, but the method can call methods that have such
parameters. Similarly, an async method can't return a value by reference, although it can call methods with ref
return values.
For more information and examples, see Async return types (C#). For more information about how to catch
exceptions in async methods, see try-catch.
Asynchronous APIs in Windows Runtime programming have one of the following return types, which are similar
to tasks:
IAsyncOperation<TResult>, which corresponds to Task<TResult>
IAsyncAction, which corresponds to Task
IAsyncActionWithProgress<TProgress>
IAsyncOperationWithProgress<TResult,TProgress>
Naming convention
By convention, methods that return commonly awaitable types (for example, Task , Task<T> , ValueTask ,
ValueTask<T> ) should have names that end with "Async". Methods that start an asynchronous operation but do
not return an awaitable type should not have names that end with "Async", but may start with "Begin", "Start", or
some other verb to suggest this method does not return or throw the result of the operation.
You can ignore the convention where an event, base class, or interface contract suggests a different name. For
example, you shouldn't rename common event handlers, such as OnButtonClick .
How to make multiple web requests in Demonstrates how to start several Async Sample: Make Multiple Web
parallel by using async and await (C#) tasks at the same time. Requests in Parallel
Cancel tasks with a cancellation token Shows how to add the following
as a signaling mechanism. functionality to your async solution:
Using async for file access (C#) Lists and demonstrates the benefits of
using async and await to access files.
See also
async
await
Asynchronous programming
Async overview
Async return types (C#)
9/3/2020 • 8 minutes to read • Edit Online
Console.WriteLine($"Today is {DateTime.Now:D}");
Console.WriteLine($"The current time is {DateTime.Now.TimeOfDay:t}");
Console.WriteLine("The current temperature is 76 degrees.");
}
WaitAndApologizeAsync is awaited by using an await statement instead of an await expression, similar to the
calling statement for a synchronous void-returning method. The application of an await operator in this case
doesn't produce a value. To clarify the terms statement and expression, refer to the table below:
You can separate the call to WaitAndApologizeAsync from the application of an await operator, as the following
code shows. However, remember that a Task doesn't have a Result property, and that no value is produced
when an await operator is applied to a Task .
The following code separates calling the WaitAndApologizeAsync method from awaiting the task that the method
returns.
string output =
$"Today is {DateTime.Now:D}\n" +
$"The current time is {DateTime.Now.TimeOfDay:t}\n" +
"The current temperature is 76 degrees.\n";
await waitAndApologizeTask;
Console.WriteLine(output);
Console.WriteLine(message);
}
int leisureHours =
today is DayOfWeek.Saturday || today is DayOfWeek.Sunday
? 16 : 5;
return leisureHours;
}
// Example output:
// Today is Wednesday, May 24, 2017
// Today's hours of leisure: 5
When GetLeisureHoursAsync is called from within an await expression in the ShowTodaysInfo method, the await
expression retrieves the integer value (the value of leisureHours ) that's stored in the task returned by the
GetLeisureHours method. For more information about await expressions, see await.
You can better understand how await retrieves the result from a Task<T> by separating the call to
GetLeisureHoursAsync from the application of await , as the following code shows. A call to method
GetLeisureHoursAsync that isn't immediately awaited returns a Task<int> , as you would expect from the
declaration of the method. The task is assigned to the getLeisureHoursTask variable in the example. Because
getLeisureHoursTask is a Task<TResult>, it contains a Result property of type TResult . In this case, TResult
represents an integer type. When await is applied to getLeisureHoursTask , the await expression evaluates to the
contents of the Result property of getLeisureHoursTask . The value is assigned to the ret variable.
IMPORTANT
The Result property is a blocking property. If you try to access it before its task is finished, the thread that's currently active
is blocked until the task completes and the value is available. In most cases, you should access the value by using await
instead of accessing the property directly.
The previous example retrieved the value of the Result property to block the main thread so that the Main method could
print the message to the console before the application ended.
string message =
$"Today is {DateTime.Today:D}\n" +
"Today's hours of leisure: " +
$"{await getLeisureHoursTask}";
Console.WriteLine(message);
using System;
using System.Threading.Tasks;
button.Clicked += OnButtonClicked1;
button.Clicked += OnButtonClicked2Async;
button.Clicked += OnButtonClicked3;
await secondHandlerFinished;
}
class Program
{
static readonly Random s_rnd = new Random();
The preceding example reads lines from a string asynchronously. Once each line is read, the code enumerates
each word in the string. Callers would enumerate each word using the await foreach statement. The method
awaits when it needs to asynchronously read the next line from the source string.
See also
FromResult
Process asynchronous tasks as they complete
Asynchronous programming with async and await (C#)
async
await
Cancel a list of tasks (C#)
9/3/2020 • 4 minutes to read • Edit Online
You can cancel an async console application if you don't want to wait for it to finish. By following the example in
this topic, you can add a cancellation to an application that downloads the contents of a list of websites. You can
cancel many tasks by associating the CancellationTokenSource instance with each task. If you select the Enter key,
you cancel all tasks that aren't yet complete.
This tutorial covers:
Creating a .NET console application
Writing an async application that supports cancellation
Demonstrating signaling cancellation
Prerequisites
This tutorial requires the following:
.NET 5.0 or later SDK
Integrated development environment (IDE)
We recommend Visual Studio, Visual Studio Code, or Visual Studio for Mac
Create example application
Create a new .NET Core console application. You can create one by using the dotnet new console command or
from Visual Studio. Open the Program.cs file in your favorite code editor.
Replace using statements
Replace the existing using statements with these declarations:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
Add fields
In the Program class definition, add these three fields:
static readonly CancellationTokenSource s_cts = new CancellationTokenSource();
Console.WriteLine("Application ending.");
}
The updated Main method is now considered an Async main, which allows for an asynchronous entry point into
the executable. It writes a few instructional messages to the console, then declares a Task instance named
cancelTask , which will read console key strokes. If the Enter key is pressed, a call to
CancellationTokenSource.Cancel() is made. This will signal cancellation. Next, the sumPageSizesTask variable is
assigned from the SumPageSizesAsync method. Both tasks are then passed to Task.WhenAny(Task[]), which will
continue when any of the two tasks have completed.
int total = 0;
foreach (string url in s_urlList)
{
int contentLength = await ProcessUrlAsync(url, s_client, s_cts.Token);
total += contentLength;
}
stopwatch.Stop();
The method starts by instantiating and starting a Stopwatch. It then loops through each URL in the s_urlList and
calls ProcessUrlAsync . With each iteration, the s_cts.Token is passed into the ProcessUrlAsync method and the
code returns a Task<TResult>, where TResult is an integer:
int total = 0;
foreach (string url in s_urlList)
{
int contentLength = await ProcessUrlAsync(url, s_client, s_cts.Token);
total += contentLength;
}
return content.Length;
}
For any given URL, the method will use the client instance provided to get the response as a byte[] . The
CancellationToken instance is passed into the HttpClient.GetAsync(String, CancellationToken) and
HttpContent.ReadAsByteArrayAsync(CancellationToken) methods. The token is used to register for requested
cancellation. The length is returned after the URL and length is written to the console.
Example application output
Application started.
Press the ENTER key to cancel...
https://docs.microsoft.com 37,357
https://docs.microsoft.com/aspnet/core 85,589
https://docs.microsoft.com/azure 398,939
https://docs.microsoft.com/azure/devops 73,663
https://docs.microsoft.com/dotnet 67,452
https://docs.microsoft.com/dynamics365 48,582
https://docs.microsoft.com/education 22,924
Application ending.
Complete example
The following code is the complete text of the Program.cs file for the example.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static readonly CancellationTokenSource s_cts = new CancellationTokenSource();
Console.WriteLine("Application ending.");
}
int total = 0;
foreach (string url in s_urlList)
{
int contentLength = await ProcessUrlAsync(url, s_client, s_cts.Token);
total += contentLength;
}
stopwatch.Stop();
return content.Length;
}
}
See also
CancellationToken
CancellationTokenSource
Asynchronous programming with async and await (C#)
Next steps
Cancel async tasks after a period of time (C#)
Cancel async tasks after a period of time (C#)
9/3/2020 • 2 minutes to read • Edit Online
You can cancel an asynchronous operation after a period of time by using the CancellationTokenSource.CancelAfter
method if you don't want to wait for the operation to finish. This method schedules the cancellation of any
associated tasks that aren't complete within the period of time that's designated by the CancelAfter expression.
This example adds to the code that's developed in Cancel a list of tasks (C#) to download a list of websites and to
display the length of the contents of each one.
This tutorial covers:
Updating an existing .NET console application
Scheduling a cancellation
Prerequisites
This tutorial requires the following:
You're expected to have created an application in the Cancel a list of tasks (C#) tutorial
.NET 5.0 or later SDK
Integrated development environment (IDE)
We recommend Visual Studio, Visual Studio Code, or Visual Studio for Mac
try
{
s_cts.CancelAfter(3500);
await SumPageSizesAsync();
}
catch (TaskCanceledException)
{
Console.WriteLine("\nTasks cancelled: timed out.\n");
}
Console.WriteLine("Application ending.");
}
The updated Main method writes a few instructional messages to the console. Within the try catch, a call to
CancellationTokenSource.CancelAfter(Int32) to schedule a cancellation. This will signal cancellation after a period of
time.
Next, the SumPageSizesAsync method is awaited. If processing all of the URLs occurs faster than the scheduled
cancellation, the application ends. However, if the scheduled cancellation is triggered before all of the URLs are
processed, a TaskCanceledException is thrown.
Example application output
Application started.
https://docs.microsoft.com 37,357
https://docs.microsoft.com/aspnet/core 85,589
https://docs.microsoft.com/azure 398,939
https://docs.microsoft.com/azure/devops 73,663
Application ending.
Complete example
The following code is the complete text of the Program.cs file for the example.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static readonly CancellationTokenSource s_cts = new CancellationTokenSource();
try
{
s_cts.CancelAfter(3500);
await SumPageSizesAsync();
}
}
catch (TaskCanceledException)
{
Console.WriteLine("\nTasks cancelled: timed out.\n");
}
Console.WriteLine("Application ending.");
}
int total = 0;
foreach (string url in s_urlList)
{
int contentLength = await ProcessUrlAsync(url, s_client, s_cts.Token);
total += contentLength;
}
stopwatch.Stop();
return content.Length;
}
}
See also
CancellationToken
CancellationTokenSource
Asynchronous programming with async and await (C#)
Cancel a list of tasks (C#)
Process asynchronous tasks as they complete (C#)
9/3/2020 • 4 minutes to read • Edit Online
By using Task.WhenAny, you can start multiple tasks at the same time and process them one by one as they're
completed rather than process them in the order in which they're started.
The following example uses a query to create a collection of tasks. Each task downloads the contents of a specified
website. In each iteration of a while loop, an awaited call to WhenAny returns the task in the collection of tasks that
finishes its download first. That task is removed from the collection and processed. The loop repeats until the
collection contains no more tasks.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
Add fields
In the Program class definition, add the following two fields:
static readonly HttpClient s_client = new HttpClient
{
MaxResponseContentBufferSize = 1_000_000
};
The HttpClient exposes the ability to send HTTP requests and receive HTTP responses. The s_urlList holds all of
the URLs that the application plans to process.
The updated Main method is now considered an Async main, which allows for an asynchronous entry point into
the executable. It is expressed a call to SumPageSizesAsync .
IEnumerable<Task<int>> downloadTasksQuery =
from url in s_urlList
select ProcessUrlAsync(url, s_client);
int total = 0;
while (downloadTasks.Any())
{
Task<int> finishedTask = await Task.WhenAny(downloadTasks);
downloadTasks.Remove(finishedTask);
total += await finishedTask;
}
stopwatch.Stop();
The method starts by instantiating and starting a Stopwatch. It then includes a query that, when executed, creates a
collection of tasks. Each call to ProcessUrlAsync in the following code returns a Task<TResult>, where TResult is
an integer:
IEnumerable<Task<int>> downloadTasksQuery =
from url in s_urlList
select ProcessUrlAsync(url, s_client);
Due to deferred execution with the LINQ, you call Enumerable.ToList to start each task.
The while loop performs the following steps for each task in the collection:
1. Awaits a call to WhenAny to identify the first task in the collection that has finished its download.
downloadTasks.Remove(firstFinishedTask);
return content.Length;
}
For any given URL, the method will use the client instance provided to get the response as a byte[] . The length
is returned after the URL and length is written to the console.
Run the program several times to verify that the downloaded lengths don't always appear in the same order.
Cau t i on
You can use WhenAny in a loop, as described in the example, to solve problems that involve a small number of
tasks. However, other approaches are more efficient if you have a large number of tasks to process. For more
information and examples, see Processing tasks as they complete.
Complete example
The following code is the complete text of the Program.cs file for the example.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
namespace ProcessTasksAsTheyFinish
{
class Program
{
static readonly HttpClient s_client = new HttpClient
{
MaxResponseContentBufferSize = 1_000_000
};
IEnumerable<Task<int>> downloadTasksQuery =
from url in s_urlList
select ProcessUrlAsync(url, s_client);
int total = 0;
while (downloadTasks.Any())
{
Task<int> finishedTask = await Task.WhenAny(downloadTasks);
downloadTasks.Remove(finishedTask);
total += await finishedTask;
}
stopwatch.Stop();
return content.Length;
}
}
}
// Example output:
// https://docs.microsoft.com/windows 25,513
// https://docs.microsoft.com/gaming 30,705
// https://docs.microsoft.com/dotnet 69,626
// https://docs.microsoft.com/dynamics365 50,756
// https://docs.microsoft.com/surface 35,519
// https://docs.microsoft.com 39,531
// https://docs.microsoft.com/azure/devops 75,837
// https://docs.microsoft.com/xamarin 60,284
// https://docs.microsoft.com/system-center 43,444
// https://docs.microsoft.com/enterprise-mobility-security 28,946
// https://docs.microsoft.com/microsoft-365 43,278
// https://docs.microsoft.com/visualstudio 31,414
// https://docs.microsoft.com/office 42,292
// https://docs.microsoft.com/azure 401,113
// https://docs.microsoft.com/graph 46,831
// https://docs.microsoft.com/education 25,098
// https://docs.microsoft.com/powershell 58,173
// https://docs.microsoft.com/aspnet/core 87,763
// https://docs.microsoft.com/sql 53,362
See also
WhenAny
Asynchronous programming with async and await (C#)
Asynchronous file access (C#)
9/3/2020 • 5 minutes to read • Edit Online
You can use the async feature to access files. By using the async feature, you can call into asynchronous methods
without using callbacks or splitting your code across multiple methods or lambda expressions. To make
synchronous code asynchronous, you just call an asynchronous method instead of a synchronous method and add
a few keywords to the code.
You might consider the following reasons for adding asynchrony to file access calls:
Asynchrony makes UI applications more responsive because the UI thread that launches the operation can
perform other work. If the UI thread must execute code that takes a long time (for example, more than 50
milliseconds), the UI may freeze until the I/O is complete and the UI thread can again process keyboard and
mouse input and other events.
Asynchrony improves the scalability of ASP.NET and other server-based applications by reducing the need for
threads. If the application uses a dedicated thread per response and a thousand requests are being handled
simultaneously, a thousand threads are needed. Asynchronous operations often don't need to use a thread
during the wait. They use the existing I/O completion thread briefly at the end.
The latency of a file access operation might be very low under current conditions, but the latency may greatly
increase in the future. For example, a file may be moved to a server that's across the world.
The added overhead of using the Async feature is small.
Asynchronous tasks can easily be run in parallel.
Write text
The following examples write text to a file. At each await statement, the method immediately exits. When the file I/O
is complete, the method resumes at the statement that follows the await statement. The async modifier is in the
definition of methods that use the await statement.
Simple example
The first statement returns a task and causes file processing to start. The second statement with the await causes
the method to immediately exit and return a different task. When the file processing later completes, execution
returns to the statement that follows the await.
Read text
The following examples read text from a file.
Simple example
Console.WriteLine(text);
}
return sb.ToString();
}
writeTaskList.Add(File.WriteAllTextAsync(filePath, text));
}
await Task.WhenAll(writeTaskList);
}
Finite control example
For each file, the WriteAsync method returns a task that is then added to a list of tasks. The
await Task.WhenAll(tasks); statement exits the method and resumes within the method when file processing is
complete for all of the tasks.
The example closes all FileStream instances in a finally block after the tasks are complete. If each FileStream
was instead created in a using statement, the FileStream might be disposed of before the task was complete.
Any performance boost is almost entirely from the parallel processing and not the asynchronous processing. The
advantages of asynchrony are that it doesn't tie up multiple threads, and that it doesn't tie up the user interface
thread.
try
{
string folder = Directory.CreateDirectory("tempfolder").Name;
IList<Task> writeTaskList = new List<Task>();
var sourceStream =
new FileStream(
filePath,
FileMode.Create, FileAccess.Write, FileShare.None,
bufferSize: 4096, useAsync: true);
writeTaskList.Add(writeTask);
}
await Task.WhenAll(writeTaskList);
}
finally
{
foreach (FileStream sourceStream in sourceStreams)
{
sourceStream.Close();
}
}
}
When using the WriteAsync and ReadAsync methods, you can specify a CancellationToken, which you can use to
cancel the operation mid-stream. For more information, see Cancellation in managed threads.
See also
Asynchronous programming with async and await (C#)
Async return types (C#)
Attributes (C#)
9/3/2020 • 5 minutes to read • Edit Online
Attributes provide a powerful method of associating metadata, or declarative information, with code (assemblies,
types, methods, properties, and so forth). After an attribute is associated with a program entity, the attribute can
be queried at run time by using a technique called reflection. For more information, see Reflection (C#).
Attributes have the following properties:
Attributes add metadata to your program. Metadata is information about the types defined in a program. All
.NET assemblies contain a specified set of metadata that describes the types and type members defined in the
assembly. You can add custom attributes to specify any additional information that is required. For more
information, see, Creating Custom Attributes (C#).
You can apply one or more attributes to entire assemblies, modules, or smaller program elements such as
classes and properties.
Attributes can accept arguments in the same way as methods and properties.
Your program can examine its own metadata or the metadata in other programs by using reflection. For more
information, see Accessing Attributes by Using Reflection (C#).
Using attributes
Attributes can be placed on most any declaration, though a specific attribute might restrict the types of
declarations on which it is valid. In C#, you specify an attribute by placing the name of the attribute enclosed in
square brackets ([]) above the declaration of the entity to which it applies.
In this example, the SerializableAttribute attribute is used to apply a specific characteristic to a class:
[Serializable]
public class SampleClass
{
// Objects of this type can be serialized.
}
A method with the attribute DllImportAttribute is declared like the following example:
[System.Runtime.InteropServices.DllImport("user32.dll")]
extern static void SampleMethod();
More than one attribute can be placed on a declaration as the following example shows:
using System.Runtime.InteropServices;
Some attributes can be specified more than once for a given entity. An example of such a multiuse attribute is
ConditionalAttribute:
[Conditional("DEBUG"), Conditional("TEST1")]
void TraceMethod()
{
// ...
}
NOTE
By convention, all attribute names end with the word "Attribute" to distinguish them from other items in the .NET libraries.
However, you do not need to specify the attribute suffix when using attributes in code. For example, [DllImport] is
equivalent to [DllImportAttribute] , but DllImportAttribute is the attribute's actual name in the .NET Class Library.
Attribute parameters
Many attributes have parameters, which can be positional, unnamed, or named. Any positional parameters must
be specified in a certain order and cannot be omitted. Named parameters are optional and can be specified in any
order. Positional parameters are specified first. For example, these three attributes are equivalent:
[DllImport("user32.dll")]
[DllImport("user32.dll", SetLastError=false, ExactSpelling=false)]
[DllImport("user32.dll", ExactSpelling=false, SetLastError=false)]
The first parameter, the DLL name, is positional and always comes first; the others are named. In this case, both
named parameters default to false, so they can be omitted. Positional parameters correspond to the parameters
of the attribute constructor. Named or optional parameters correspond to either properties or fields of the
attribute. Refer to the individual attribute's documentation for information on default parameter values.
Attribute targets
The target of an attribute is the entity which the attribute applies to. For example, an attribute may apply to a
class, a particular method, or an entire assembly. By default, an attribute applies to the element that follows it. But
you can also explicitly identify, for example, whether an attribute is applied to a method, or to its parameter, or to
its return value.
To explicitly identify an attribute target, use the following syntax:
[target : attribute-list]
TA RGET VA L UE A P P L IES TO
event Event
property Property
You would specify the field target value to apply an attribute to the backing field created for an auto-
implemented property.
The following example shows how to apply attributes to assemblies and modules. For more information, see
Common Attributes (C#).
using System;
using System.Reflection;
[assembly: AssemblyTitleAttribute("Production assembly 4")]
[module: CLSCompliant(true)]
The following example shows how to apply attributes to methods, method parameters, and method return values
in C#.
// applies to method
[method: ValidatedContract]
int Method2() { return 0; }
NOTE
Regardless of the targets on which ValidatedContract is defined to be valid, the return target has to be specified,
even if ValidatedContract were defined to apply only to return values. In other words, the compiler will not use
AttributeUsage information to resolve ambiguous attribute targets. For more information, see AttributeUsage (C#).
Related sections
For more information, see:
Creating Custom Attributes (C#)
Accessing Attributes by Using Reflection (C#)
How to create a C/C++ union by using attributes (C#)
Common Attributes (C#)
Caller Information (C#)
See also
C# Programming Guide
Reflection (C#)
Attributes
Using Attributes in C#
Creating Custom Attributes (C#)
9/3/2020 • 2 minutes to read • Edit Online
You can create your own custom attributes by defining an attribute class, a class that derives directly or indirectly
from Attribute, which makes identifying attribute definitions in metadata fast and easy. Suppose you want to tag
types with the name of the programmer who wrote the type. You might define a custom Author attribute class:
[System.AttributeUsage(System.AttributeTargets.Class |
System.AttributeTargets.Struct)
]
public class AuthorAttribute : System.Attribute
{
private string name;
public double version;
The class name AuthorAttribute is the attribute's name, Author , plus the Attribute suffix. It is derived from
System.Attribute , so it is a custom attribute class. The constructor's parameters are the custom attribute's
positional parameters. In this example, name is a positional parameter. Any public read-write fields or properties
are named parameters. In this case, version is the only named parameter. Note the use of the AttributeUsage
attribute to make the Author attribute valid only on class and struct declarations.
You could use this new attribute as follows:
AttributeUsage has a named parameter, AllowMultiple , with which you can make a custom attribute single-use
or multiuse. In the following code example, a multiuse attribute is created.
[System.AttributeUsage(System.AttributeTargets.Class |
System.AttributeTargets.Struct,
AllowMultiple = true) // multiuse attribute
]
public class AuthorAttribute : System.Attribute
In the following code example, multiple attributes of the same type are applied to a class.
[Author("P. Ackerman", version = 1.1)]
[Author("R. Koch", version = 1.2)]
class SampleClass
{
// P. Ackerman's code goes here...
// R. Koch's code goes here...
}
See also
System.Reflection
C# Programming Guide
Writing Custom Attributes
Reflection (C#)
Attributes (C#)
Accessing Attributes by Using Reflection (C#)
AttributeUsage (C#)
Accessing Attributes by Using Reflection (C#)
9/3/2020 • 2 minutes to read • Edit Online
The fact that you can define custom attributes and place them in your source code would be of little value without
some way of retrieving that information and acting on it. By using reflection, you can retrieve the information that
was defined with custom attributes. The key method is GetCustomAttributes , which returns an array of objects that
are the run-time equivalents of the source code attributes. This method has several overloaded versions. For more
information, see Attribute.
An attribute specification such as:
However, the code is not executed until SampleClass is queried for attributes. Calling GetCustomAttributes on
SampleClass causes an Author object to be constructed and initialized as above. If the class has other attributes,
other attribute objects are constructed similarly. GetCustomAttributes then returns the Author object and any
other attribute objects in an array. You can then iterate over this array, determine what attributes were applied
based on the type of each array element, and extract information from the attribute objects.
Example
Here is a complete example. A custom attribute is defined, applied to several entities, and retrieved via reflection.
// Multiuse attribute.
[System.AttributeUsage(System.AttributeTargets.Class |
System.AttributeTargets.Struct,
AllowMultiple = true) // Multiuse attribute.
]
public class Author : System.Attribute
{
string name;
public double version;
// Default value.
version = 1.0;
}
class TestAuthorAttribute
{
static void Test()
{
PrintAuthorInfo(typeof(FirstClass));
PrintAuthorInfo(typeof(SecondClass));
PrintAuthorInfo(typeof(ThirdClass));
}
// Using reflection.
System.Attribute[] attrs = System.Attribute.GetCustomAttributes(t); // Reflection.
// Displaying output.
foreach (System.Attribute attr in attrs)
{
if (attr is Author)
{
Author a = (Author)attr;
System.Console.WriteLine(" {0}, version {1:f}", a.GetName(), a.version);
}
}
}
}
/* Output:
Author information for FirstClass
P. Ackerman, version 1.00
Author information for SecondClass
Author information for ThirdClass
R. Koch, version 2.00
P. Ackerman, version 1.00
*/
See also
System.Reflection
Attribute
C# Programming Guide
Retrieving Information Stored in Attributes
Reflection (C#)
Attributes (C#)
Creating Custom Attributes (C#)
How to create a C/C++ union by using attributes
(C#)
9/3/2020 • 2 minutes to read • Edit Online
By using attributes, you can customize how structs are laid out in memory. For example, you can create what is
known as a union in C/C++ by using the StructLayout(LayoutKind.Explicit) and FieldOffset attributes.
Example
In this code segment, all of the fields of TestUnion start at the same location in memory.
[System.Runtime.InteropServices.StructLayout(LayoutKind.Explicit)]
struct TestUnion
{
[System.Runtime.InteropServices.FieldOffset(0)]
public int i;
[System.Runtime.InteropServices.FieldOffset(0)]
public double d;
[System.Runtime.InteropServices.FieldOffset(0)]
public char c;
[System.Runtime.InteropServices.FieldOffset(0)]
public byte b;
}
Example
The following is another example where fields start at different explicitly set locations.
// Add a using directive for System.Runtime.InteropServices.
[System.Runtime.InteropServices.StructLayout(LayoutKind.Explicit)]
struct TestExplicit
{
[System.Runtime.InteropServices.FieldOffset(0)]
public long lg;
[System.Runtime.InteropServices.FieldOffset(0)]
public int i1;
[System.Runtime.InteropServices.FieldOffset(4)]
public int i2;
[System.Runtime.InteropServices.FieldOffset(8)]
public double d;
[System.Runtime.InteropServices.FieldOffset(12)]
public char c;
[System.Runtime.InteropServices.FieldOffset(14)]
public byte b;
}
The two integer fields, i1 and i2 , share the same memory locations as lg . This sort of control over struct
layout is useful when using platform invocation.
See also
System.Reflection
Attribute
C# Programming Guide
Attributes
Reflection (C#)
Attributes (C#)
Creating Custom Attributes (C#)
Accessing Attributes by Using Reflection (C#)
Collections (C#)
9/3/2020 • 13 minutes to read • Edit Online
For many applications, you want to create and manage groups of related objects. There are two ways to group
objects: by creating arrays of objects, and by creating collections of objects.
Arrays are most useful for creating and working with a fixed number of strongly typed objects. For information
about arrays, see Arrays.
Collections provide a more flexible way to work with groups of objects. Unlike arrays, the group of objects you
work with can grow and shrink dynamically as the needs of the application change. For some collections, you can
assign a key to any object that you put into the collection so that you can quickly retrieve the object by using the
key.
A collection is a class, so you must declare an instance of the class before you can add elements to that collection.
If your collection contains elements of only one data type, you can use one of the classes in the
System.Collections.Generic namespace. A generic collection enforces type safety so that no other data type can be
added to it. When you retrieve an element from a generic collection, you do not have to determine its data type or
convert it.
NOTE
For the examples in this topic, include using directives for the System.Collections.Generic and System.Linq
namespaces.
In this topic
Using a Simple Collection
Kinds of Collections
System.Collections.Generic Classes
System.Collections.Concurrent Classes
System.Collections Classes
Implementing a Collection of Key/Value Pairs
Using LINQ to Access a Collection
Sorting a Collection
Defining a Custom Collection
Iterators
If the contents of a collection are known in advance, you can use a collection initializer to initialize the collection.
For more information, see Object and Collection Initializers.
The following example is the same as the previous example, except a collection initializer is used to add elements
to the collection.
You can use a for statement instead of a foreach statement to iterate through a collection. You accomplish this by
accessing the collection elements by the index position. The index of the elements starts at 0 and ends at the
element count minus 1.
The following example iterates through the elements of a collection by using for instead of foreach .
The following example removes an element from the collection by specifying the object to remove.
// Create a list of strings by using a
// collection initializer.
var salmons = new List<string> { "chinook", "coho", "pink", "sockeye" };
The following example removes elements from a generic list. Instead of a foreach statement, a for statement that
iterates in descending order is used. This is because the RemoveAt method causes elements after a removed
element to have a lower index value.
For the type of elements in the List<T>, you can also define your own class. In the following example, the Galaxy
class that is used by the List<T> is defined in the code.
private static void IterateThroughList()
{
var theGalaxies = new List<Galaxy>
{
new Galaxy() { Name="Tadpole", MegaLightYears=400},
new Galaxy() { Name="Pinwheel", MegaLightYears=25},
new Galaxy() { Name="Milky Way", MegaLightYears=0},
new Galaxy() { Name="Andromeda", MegaLightYears=3}
};
// Output:
// Tadpole 400
// Pinwheel 25
// Milky Way 0
// Andromeda 3
}
Kinds of Collections
Many common collections are provided by .NET. Each type of collection is designed for a specific purpose.
Some of the common collection classes are described in this section:
System.Collections.Generic classes
System.Collections.Concurrent classes
System.Collections classes
System.Collections.Generic Classes
You can create a generic collection by using one of the classes in the System.Collections.Generic namespace. A
generic collection is useful when every item in the collection has the same data type. A generic collection enforces
strong typing by allowing only the desired data type to be added.
The following table lists some of the frequently used classes of the System.Collections.Generic namespace:
C L A SS DESC RIP T IO N
For additional information, see Commonly Used Collection Types, Selecting a Collection Class, and
System.Collections.Generic.
System.Collections.Concurrent Classes
In .NET Framework 4 and later versions, the collections in the System.Collections.Concurrent namespace provide
efficient thread-safe operations for accessing collection items from multiple threads.
The classes in the System.Collections.Concurrent namespace should be used instead of the corresponding types in
the System.Collections.Generic and System.Collections namespaces whenever multiple threads are accessing the
collection concurrently. For more information, see Thread-Safe Collections and System.Collections.Concurrent.
Some classes included in the System.Collections.Concurrent namespace are BlockingCollection<T>,
ConcurrentDictionary<TKey,TValue>, ConcurrentQueue<T>, and ConcurrentStack<T>.
System.Collections Classes
The classes in the System.Collections namespace do not store elements as specifically typed objects, but as objects
of type Object .
Whenever possible, you should use the generic collections in the System.Collections.Generic namespace or the
System.Collections.Concurrent namespace instead of the legacy types in the System.Collections namespace.
The following table lists some of the frequently used classes in the System.Collections namespace:
C L A SS DESC RIP T IO N
The System.Collections.Specialized namespace provides specialized and strongly typed collection classes, such as
string-only collections and linked-list and hybrid dictionaries.
return elements;
}
theElement.Symbol = symbol;
theElement.Name = name;
theElement.AtomicNumber = atomicNumber;
To instead use a collection initializer to build the Dictionary collection, you can replace the BuildDictionary and
AddToDictionary methods with the following method.
The following example uses the ContainsKey method and the Item[] property of Dictionary to quickly find an
item by key. The Item property enables you to access an item in the elements collection by using the
elements[symbol] in C#.
if (elements.ContainsKey(symbol) == false)
{
Console.WriteLine(symbol + " not found");
}
else
{
Element theElement = elements[symbol];
Console.WriteLine("found: " + theElement.Name);
}
}
The following example instead uses the TryGetValue method quickly find an item by key.
// LINQ Query.
var subset = from theElement in elements
where theElement.AtomicNumber < 22
orderby theElement.Name
select theElement;
// Output:
// Calcium 20
// Potassium 19
// Scandium 21
}
Sorting a Collection
The following example illustrates a procedure for sorting a collection. The example sorts instances of the Car
class that are stored in a List<T>. The Car class implements the IComparable<T> interface, which requires that
the CompareTo method be implemented.
Each call to the CompareTo method makes a single comparison that is used for sorting. User-written code in the
CompareTo method returns a value for each comparison of the current object with another object. The value
returned is less than zero if the current object is less than the other object, greater than zero if the current object is
greater than the other object, and zero if they are equal. This enables you to define in code the criteria for greater
than, less than, and equal.
In the ListCars method, the cars.Sort() statement sorts the list. This call to the Sort method of the List<T>
causes the CompareTo method to be called automatically for the Car objects in the List .
// Output:
// blue 50 car4
// blue 30 car5
// blue 20 car1
// green 50 car7
// green 10 car3
// red 60 car6
// red 50 car2
}
return compare;
}
}
// Collection class.
public class AllColors : System.Collections.IEnumerable
{
Color[] _colors =
{
new Color() { Name = "red" },
new Color() { Name = "blue" },
new Color() { Name = "green" }
};
// Custom enumerator.
private class ColorEnumerator : System.Collections.IEnumerator
{
private Color[] _colors;
private int _position = -1;
object System.Collections.IEnumerator.Current
{
get
{
return _colors[_position];
}
}
bool System.Collections.IEnumerator.MoveNext()
{
_position++;
return (_position < _colors.Length);
}
void System.Collections.IEnumerator.Reset()
{
_position = -1;
}
}
}
}
// Element class.
public class Color
{
public string Name { get; set; }
}
Iterators
An iterator is used to perform a custom iteration over a collection. An iterator can be a method or a get accessor.
An iterator uses a yield return statement to return each element of the collection one at a time.
You call an iterator by using a foreach statement. Each iteration of the foreach loop calls the iterator. When a
yield return statement is reached in the iterator, an expression is returned, and the current location in code is
retained. Execution is restarted from that location the next time that the iterator is called.
For more information, see Iterators (C#).
The following example uses an iterator method. The iterator method has a yield return statement that is inside a
for loop. In the ListEvenNumbers method, each iteration of the foreach statement body creates a call to the
iterator method, which proceeds to the next yield return statement.
See also
Object and Collection Initializers
Programming Concepts (C#)
Option Strict Statement
LINQ to Objects (C#)
Parallel LINQ (PLINQ)
Collections and Data Structures
Selecting a Collection Class
Comparisons and Sorts Within Collections
When to Use Generic Collections
Covariance and Contravariance (C#)
9/3/2020 • 3 minutes to read • Edit Online
In C#, covariance and contravariance enable implicit reference conversion for array types, delegate types, and
generic type arguments. Covariance preserves assignment compatibility and contravariance reverses it.
The following code demonstrates the difference between assignment compatibility, covariance, and
contravariance.
// Assignment compatibility.
string str = "test";
// An object of a more derived type is assigned to an object of a less derived type.
object obj = str;
// Covariance.
IEnumerable<string> strings = new List<string>();
// An object that is instantiated with a more derived type argument
// is assigned to an object instantiated with a less derived type argument.
// Assignment compatibility is preserved.
IEnumerable<object> objects = strings;
// Contravariance.
// Assume that the following method is in the class:
// static void SetObject(object o) { }
Action<object> actObject = SetObject;
// An object that is instantiated with a less derived type argument
// is assigned to an object instantiated with a more derived type argument.
// Assignment compatibility is reversed.
Action<string> actString = actObject;
Covariance for arrays enables implicit conversion of an array of a more derived type to an array of a less derived
type. But this operation is not type safe, as shown in the following code example.
Covariance and contravariance support for method groups allows for matching method signatures with delegate
types. This enables you to assign to delegates not only methods that have matching signatures, but also methods
that return more derived types (covariance) or that accept parameters that have less derived types
(contravariance) than that specified by the delegate type. For more information, see Variance in Delegates (C#) and
Using Variance in Delegates (C#).
The following code example shows covariance and contravariance support for method groups.
static object GetObject() { return null; }
static void SetObject(object obj) { }
In .NET Framework 4 and later versions, C# supports covariance and contravariance in generic interfaces and
delegates and allows for implicit conversion of generic type parameters. For more information, see Variance in
Generic Interfaces (C#) and Variance in Delegates (C#).
The following code example shows implicit reference conversion for generic interfaces.
A generic interface or delegate is called variant if its generic parameters are declared covariant or contravariant.
C# enables you to create your own variant interfaces and delegates. For more information, see Creating Variant
Generic Interfaces (C#) and Variance in Delegates (C#).
Related Topics
T IT L E DESC RIP T IO N
Variance in Generic Interfaces (C#) Discusses covariance and contravariance in generic interfaces
and provides a list of variant generic interfaces in the .NET
Framework.
Creating Variant Generic Interfaces (C#) Shows how to create custom variant interfaces.
Using Variance in Interfaces for Generic Collections (C#) Shows how covariance and contravariance support in the
IEnumerable<T> and IComparable<T> interfaces can help
you reuse code.
Variance in Delegates (C#) Discusses covariance and contravariance in generic and non-
generic delegates and provides a list of variant generic
delegates in the .NET Framework.
Using Variance in Delegates (C#) Shows how to use covariance and contravariance support in
non-generic delegates to match method signatures with
delegate types.
Using Variance for Func and Action Generic Delegates (C#) Shows how covariance and contravariance support in the
Func and Action delegates can help you reuse code.
Variance in Generic Interfaces (C#)
9/3/2020 • 2 minutes to read • Edit Online
.NET Framework 4 introduced variance support for several existing generic interfaces. Variance support enables
implicit conversion of classes that implement these interfaces.
Starting with .NET Framework 4, the following interfaces are variant:
IEnumerable<T> (T is covariant)
IEnumerator<T> (T is covariant)
IQueryable<T> (T is covariant)
IGrouping<TKey,TElement> ( TKey and TElement are covariant)
IComparer<T> (T is contravariant)
IEqualityComparer<T> (T is contravariant)
IComparable<T> (T is contravariant)
Starting with .NET Framework 4.5, the following interfaces are variant:
IReadOnlyList<T> (T is covariant)
IReadOnlyCollection<T> (T is covariant)
Covariance permits a method to have a more derived return type than that defined by the generic type parameter
of the interface. To illustrate the covariance feature, consider these generic interfaces: IEnumerable<Object> and
IEnumerable<String> . The IEnumerable<String> interface does not inherit the IEnumerable<Object> interface.
However, the String type does inherit the Object type, and in some cases you may want to assign objects of
these interfaces to each other. This is shown in the following code example.
In earlier versions of .NET Framework, this code causes a compilation error in C# and, if Option Strict is on, in
Visual Basic. But now you can use strings instead of objects , as shown in the previous example, because the
IEnumerable<T> interface is covariant.
Contravariance permits a method to have argument types that are less derived than that specified by the generic
parameter of the interface. To illustrate contravariance, assume that you have created a BaseComparer class to
compare instances of the BaseClass class. The BaseComparer class implements the IEqualityComparer<BaseClass>
interface. Because the IEqualityComparer<T> interface is now contravariant, you can use BaseComparer to
compare instances of classes that inherit the BaseClass class. This is shown in the following code example.
// Simple hierarchy of classes.
class BaseClass { }
class DerivedClass : BaseClass { }
// Comparer class.
class BaseComparer : IEqualityComparer<BaseClass>
{
public int GetHashCode(BaseClass baseInstance)
{
return baseInstance.GetHashCode();
}
public bool Equals(BaseClass x, BaseClass y)
{
return x == y;
}
}
class Program
{
static void Test()
{
IEqualityComparer<BaseClass> baseComparer = new BaseComparer();
For more examples, see Using Variance in Interfaces for Generic Collections (C#).
Variance in generic interfaces is supported for reference types only. Value types do not support variance. For
example, IEnumerable<int> cannot be implicitly converted to IEnumerable<object> , because integers are
represented by a value type.
It is also important to remember that classes that implement variant interfaces are still invariant. For example,
although List<T> implements the covariant interface IEnumerable<T>, you cannot implicitly convert
List<String> to List<Object> . This is illustrated in the following code example.
See also
Using Variance in Interfaces for Generic Collections (C#)
Creating Variant Generic Interfaces (C#)
Generic Interfaces
Variance in Delegates (C#)
Creating Variant Generic Interfaces (C#)
9/3/2020 • 4 minutes to read • Edit Online
You can declare generic type parameters in interfaces as covariant or contravariant. Covariance allows interface
methods to have more derived return types than that defined by the generic type parameters. Contravariance
allows interface methods to have argument types that are less derived than that specified by the generic
parameters. A generic interface that has covariant or contravariant generic type parameters is called variant.
NOTE
.NET Framework 4 introduced variance support for several existing generic interfaces. For the list of the variant interfaces in
.NET, see Variance in Generic Interfaces (C#).
IMPORTANT
ref , in , and out parameters in C# cannot be variant. Value types also do not support variance.
You can declare a generic type parameter covariant by using the out keyword. The covariant type must satisfy the
following conditions:
The type is used only as a return type of interface methods and not used as a type of method arguments.
This is illustrated in the following example, in which the type R is declared covariant.
There is one exception to this rule. If you have a contravariant generic delegate as a method parameter, you
can use the type as a generic type parameter for the delegate. This is illustrated by the type R in the
following example. For more information, see Variance in Delegates (C#) and Using Variance for Func and
Action Generic Delegates (C#).
The type is not used as a generic constraint for the interface methods. This is illustrated in the following
code.
interface ICovariant<out R>
{
// The following statement generates a compiler error
// because you can use only contravariant or invariant types
// in generic constraints.
// void DoSomething<T>() where T : R;
}
You can declare a generic type parameter contravariant by using the in keyword. The contravariant type can be
used only as a type of method arguments and not as a return type of interface methods. The contravariant type
can also be used for generic constraints. The following code shows how to declare a contravariant interface and
use a generic constraint for one of its methods.
It is also possible to support both covariance and contravariance in the same interface, but for different type
parameters, as shown in the following code example.
Classes that implement variant interfaces are invariant. For example, consider the following code.
// The interface is covariant.
ICovariant<Button> ibutton = new SampleImplementation<Button>();
ICovariant<Object> iobj = ibutton;
In the IInvariant<T> interface, the generic type parameter T is invariant, whereas in IExtCovariant<out T> the
type parameter is covariant, although both interfaces extend the same interface. The same rule is applied to
contravariant generic type parameters.
You can create an interface that extends both the interface where the generic type parameter T is covariant and
the interface where it is contravariant if in the extending interface the generic type parameter T is invariant. This
is illustrated in the following code example.
However, if a generic type parameter T is declared covariant in one interface, you cannot declare it contravariant
in the extending interface, or vice versa. This is illustrated in the following code example.
Avoiding Ambiguity
When you implement variant generic interfaces, variance can sometimes lead to ambiguity. Such ambiguity should
be avoided.
For example, if you explicitly implement the same variant generic interface with different generic type parameters
in one class, it can create ambiguity. The compiler does not produce an error in this case, but it's not specified
which interface implementation will be chosen at run time. This ambiguity could lead to subtle bugs in your code.
Consider the following code example.
// Simple class hierarchy.
class Animal { }
class Cat : Animal { }
class Dog : Animal { }
IEnumerator IEnumerable.GetEnumerator()
{
// Some code.
return null;
}
IEnumerator<Dog> IEnumerable<Dog>.GetEnumerator()
{
Console.WriteLine("Dog");
// Some code.
return null;
}
}
class Program
{
public static void Test()
{
IEnumerable<Animal> pets = new Pets();
pets.GetEnumerator();
}
}
In this example, it is unspecified how the pets.GetEnumerator method chooses between Cat and Dog . This could
cause problems in your code.
See also
Variance in Generic Interfaces (C#)
Using Variance for Func and Action Generic Delegates (C#)
Using Variance in Interfaces for Generic Collections
(C#)
9/3/2020 • 2 minutes to read • Edit Online
A covariant interface allows its methods to return more derived types than those specified in the interface. A
contravariant interface allows its methods to accept parameters of less derived types than those specified in the
interface.
In .NET Framework 4, several existing interfaces became covariant and contravariant. These include
IEnumerable<T> and IComparable<T>. This enables you to reuse methods that operate with generic collections of
base types for collections of derived types.
For a list of variant interfaces in .NET, see Variance in Generic Interfaces (C#).
class Program
{
// The method has a parameter of the IEnumerable<Person> type.
public static void PrintFullName(IEnumerable<Person> persons)
{
foreach (Person person in persons)
{
Console.WriteLine("Name: {0} {1}",
person.FirstName, person.LastName);
}
}
PrintFullName(employees);
}
}
class Program
{
IEnumerable<Employee> noduplicates =
employees.Distinct<Employee>(new PersonComparer());
See also
Variance in Generic Interfaces (C#)
Variance in Delegates (C#)
9/3/2020 • 5 minutes to read • Edit Online
.NET Framework 3.5 introduced variance support for matching method signatures with delegate types in all
delegates in C#. This means that you can assign to delegates not only methods that have matching signatures,
but also methods that return more derived types (covariance) or that accept parameters that have less derived
types (contravariance) than that specified by the delegate type. This includes both generic and non-generic
delegates.
For example, consider the following code, which has two classes and two delegates: generic and non-generic.
When you create delegates of the SampleDelegate or SampleGenericDelegate<A, R> types, you can assign any one
of the following methods to those delegates.
// Matching signature.
public static First ASecondRFirst(Second second)
{ return new First(); }
The following code example illustrates the implicit conversion between the method signature and the delegate
type.
If you use only variance support to match method signatures with delegate types and do not use the in and
out keywords, you may find that sometimes you can instantiate delegates with identical lambda expressions or
methods, but you cannot assign one delegate to another.
In the following code example, SampleGenericDelegate<String> cannot be explicitly converted to
SampleGenericDelegate<Object> , although String inherits Object . You can fix this problem by marking the
generic parameter T with the out keyword.
You can declare a generic type parameter contravariant in a generic delegate by using the in keyword. The
contravariant type can be used only as a type of method arguments and not as a method return type. The
following code example shows how to declare a contravariant generic delegate.
IMPORTANT
ref , in , and out parameters in C# can't be marked as variant.
It is also possible to support both variance and covariance in the same delegate, but for different type
parameters. This is shown in the following example.
See also
Generics
Using Variance for Func and Action Generic Delegates (C#)
How to combine delegates (Multicast Delegates)
Using Variance in Delegates (C#)
9/3/2020 • 2 minutes to read • Edit Online
When you assign a method to a delegate, covariance and contravariance provide flexibility for matching a
delegate type with a method signature. Covariance permits a method to have return type that is more derived
than that defined in the delegate. Contravariance permits a method that has parameter types that are less derived
than those in the delegate type.
Example 1: Covariance
Description
This example demonstrates how delegates can be used with methods that have return types that are derived from
the return type in the delegate signature. The data type returned by DogsHandler is of type Dogs , which derives
from the Mammals type that is defined in the delegate.
Code
class Mammals {}
class Dogs : Mammals {}
class Program
{
// Define the delegate.
public delegate Mammals HandlerMethod();
Example 2: Contravariance
Description
This example demonstrates how delegates can be used with methods that have parameters whose types are base
types of the delegate signature parameter type. With contravariance, you can use one event handler instead of
separate handlers. The following example makes use of two delegates:
A KeyEventHandler delegate that defines the signature of the Button.KeyDown event. Its signature is:
public delegate void KeyEventHandler(object sender, KeyEventArgs e)
A MouseEventHandler delegate that defines the signature of the Button.MouseClick event. Its signature is:
The example defines an event handler with an EventArgs parameter and uses it to handle both the
Button.KeyDown and Button.MouseClick events. It can do this because EventArgs is a base type of both
KeyEventArgs and MouseEventArgs.
Code
public Form1()
{
InitializeComponent();
See also
Variance in Delegates (C#)
Using Variance for Func and Action Generic Delegates (C#)
Using Variance for Func and Action Generic
Delegates (C#)
9/3/2020 • 2 minutes to read • Edit Online
These examples demonstrate how to use covariance and contravariance in the Func and Action generic
delegates to enable reuse of methods and provide more flexibility in your code.
For more information about covariance and contravariance, see Variance in Delegates (C#).
}
}
See also
Covariance and Contravariance (C#)
Generics
Expression Trees (C#)
9/3/2020 • 4 minutes to read • Edit Online
Expression trees represent code in a tree-like data structure, where each node is an expression, for example, a
method call or a binary operation such as x < y .
You can compile and run code represented by expression trees. This enables dynamic modification of executable
code, the execution of LINQ queries in various databases, and the creation of dynamic queries. For more
information about expression trees in LINQ, see How to use expression trees to build dynamic queries (C#).
Expression trees are also used in the dynamic language runtime (DLR) to provide interoperability between
dynamic languages and .NET and to enable compiler writers to emit expression trees instead of Microsoft
intermediate language (MSIL). For more information about the DLR, see Dynamic Language Runtime Overview.
You can have the C# or Visual Basic compiler create an expression tree for you based on an anonymous lambda
expression, or you can create expression trees manually by using the System.Linq.Expressions namespace.
In .NET Framework 4 or later, the expression trees API also supports assignments and control flow expressions
such as loops, conditional blocks, and try-catch blocks. By using the API, you can create expression trees that are
more complex than those that can be created from lambda expressions by the C# compiler. The following
example demonstrates how to create an expression tree that calculates the factorial of a number.
Console.WriteLine(factorial);
// Prints 120.
For more information, see Generating Dynamic Methods with Expression Trees in Visual Studio 2010, which also
applies to later versions of Visual Studio.
// Prints True.
See also
System.Linq.Expressions
How to execute expression trees (C#)
How to modify expression trees (C#)
Lambda Expressions
Dynamic Language Runtime Overview
Programming Concepts (C#)
How to execute expression trees (C#)
9/3/2020 • 2 minutes to read • Edit Online
This topic shows you how to execute an expression tree. Executing an expression tree may return a value, or it may
just perform an action such as calling a method.
Only expression trees that represent lambda expressions can be executed. Expression trees that represent lambda
expressions are of type LambdaExpression or Expression<TDelegate>. To execute these expression trees, call the
Compile method to create an executable delegate, and then invoke the delegate.
NOTE
If the type of the delegate is not known, that is, the lambda expression is of type LambdaExpression and not
Expression<TDelegate>, you must call the DynamicInvoke method on the delegate instead of invoking it directly.
If an expression tree does not represent a lambda expression, you can create a new lambda expression that has the
original expression tree as its body, by calling the Lambda<TDelegate>(Expression,
IEnumerable<ParameterExpression>) method. Then, you can execute the lambda expression as described earlier in
this section.
Example
The following code example demonstrates how to execute an expression tree that represents raising a number to a
power by creating a lambda expression and executing it. The result, which represents the number raised to the
power, is displayed.
See also
Expression Trees (C#)
How to modify expression trees (C#)
How to modify expression trees (C#)
9/3/2020 • 2 minutes to read • Edit Online
This topic shows you how to modify an expression tree. Expression trees are immutable, which means that they
cannot be modified directly. To change an expression tree, you must create a copy of an existing expression tree
and when you create the copy, make the required changes. You can use the ExpressionVisitor class to traverse an
existing expression tree and to copy each node that it visits.
To modify an expression tree
1. Create a new Console Application project.
2. Add a using directive to the file for the System.Linq.Expressions namespace.
3. Add the AndAlsoModifier class to your project.
return base.VisitBinary(b);
}
}
This class inherits the ExpressionVisitor class and is specialized to modify expressions that represent
conditional AND operations. It changes these operations from a conditional AND to a conditional OR . To do
this, the class overrides the VisitBinary method of the base type, because conditional AND expressions are
represented as binary expressions. In the VisitBinary method, if the expression that is passed to it
represents a conditional AND operation, the code constructs a new expression that contains the conditional
OR operator instead of the conditional AND operator. If the expression that is passed to VisitBinary does
not represent a conditional AND operation, the method defers to the base class implementation. The base
class methods construct nodes that are like the expression trees that are passed in, but the nodes have their
sub trees replaced with the expression trees that are produced recursively by the visitor.
4. Add a using directive to the file for the System.Linq.Expressions namespace.
5. Add code to the Main method in the Program.cs file to create an expression tree and pass it to the method
that will modify it.
Expression<Func<string, bool>> expr = name => name.Length > 10 && name.StartsWith("G");
Console.WriteLine(expr);
Console.WriteLine(modifiedExpr);
The code creates an expression that contains a conditional AND operation. It then creates an instance of the
AndAlsoModifier class and passes the expression to the Modify method of this class. Both the original and
the modified expression trees are outputted to show the change.
6. Compile and run the application.
See also
How to execute expression trees (C#)
Expression Trees (C#)
How to use expression trees to build dynamic queries
(C#)
9/3/2020 • 3 minutes to read • Edit Online
In LINQ, expression trees are used to represent structured queries that target sources of data that implement
IQueryable<T>. For example, the LINQ provider implements the IQueryable<T> interface for querying relational
data stores. The C# compiler compiles queries that target such data sources into code that builds an expression tree
at runtime. The query provider can then traverse the expression tree data structure and translate it into a query
language appropriate for the data source.
Expression trees are also used in LINQ to represent lambda expressions that are assigned to variables of type
Expression<TDelegate>.
This topic describes how to use expression trees to create dynamic LINQ queries. Dynamic queries are useful when
the specifics of a query are not known at compile time. For example, an application might provide a user interface
that enables the end user to specify one or more predicates to filter the data. In order to use LINQ for querying, this
kind of application must use expression trees to create the LINQ query at runtime.
Example
The following example shows you how to use expression trees to construct a query against an IQueryable data
source and then execute it. The code builds an expression tree to represent the following query:
The factory methods in the System.Linq.Expressions namespace are used to create expression trees that represent
the expressions that make up the overall query. The expressions that represent calls to the standard query operator
methods refer to the Queryable implementations of these methods. The final expression tree is passed to the
CreateQuery<TElement>(Expression) implementation of the provider of the IQueryable data source to create an
executable query of type IQueryable . The results are obtained by enumerating that query variable.
string[] companies = { "Consolidated Messenger", "Alpine Ski House", "Southridge Video", "City Power & Light",
"Coho Winery", "Wide World Importers", "Graphic Design Institute", "Adventure Works",
"Humongous Insurance", "Woodgrove Bank", "Margie's Travel", "Northwind Traders",
"Blue Yonder Airlines", "Trey Research", "The Phone Company",
"Wingtip Toys", "Lucerne Publishing", "Fourth Coffee" };
// Compose the expression tree that represents the parameter to the predicate.
ParameterExpression pe = Expression.Parameter(typeof(string), "company");
// ***** Where(company => (company.ToLower() == "coho winery" || company.Length > 16)) *****
// Create an expression tree that represents the expression 'company.ToLower() == "coho winery"'.
Expression left = Expression.Call(pe, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));
Expression right = Expression.Constant("coho winery");
Expression e1 = Expression.Equal(left, right);
// Create an expression tree that represents the expression 'company.Length > 16'.
left = Expression.Property(pe, typeof(string).GetProperty("Length"));
left = Expression.Property(pe, typeof(string).GetProperty("Length"));
right = Expression.Constant(16, typeof(int));
Expression e2 = Expression.GreaterThan(left, right);
// Combine the expression trees to create an expression tree that represents the
// expression '(company.ToLower() == "coho winery" || company.Length > 16)'.
Expression predicateBody = Expression.OrElse(e1, e2);
This code uses a fixed number of expressions in the predicate that is passed to the Queryable.Where method.
However, you can write an application that combines a variable number of predicate expressions that depends on
the user input. You can also vary the standard query operators that are called in the query, depending on the input
from the user.
See also
Expression Trees (C#)
How to execute expression trees (C#)
Dynamically specify predicate filters at runtime
Debugging Expression Trees in Visual Studio (C#)
9/3/2020 • 2 minutes to read • Edit Online
You can analyze the structure and content of expression trees when you debug your applications. To get a quick
overview of the expression tree structure, you can use the DebugView property, which represents expression trees
using a special syntax. (Note that DebugView is available only in debug mode.)
Since DebugView is a string, you can use the built-in Text Visualizer to view it across multiple lines, by selecting Text
Visualizer from the magnifying glass icon next to the DebugView label.
Alternatively, you can install and use a custom visualizer for expression trees, such as:
Readable Expressions (MIT license, available at the Visual Studio Marketplace), renders the expression tree as
themeable C# code, with various rendering options:
Expression Tree Visualizer (MIT license) provides a tree view of the expression tree and its individual nodes:
To open a visualizer for an expression tree
1. Click the magnifying glass icon that appears next to the expression tree in DataTips , a Watch window, the
Autos window, or the Locals window.
A list of available visualizers is displayed.:
See also
Expression Trees (C#)
Debugging in Visual Studio
Create Custom Visualizers
DebugView syntax
DebugView syntax
7/9/2019 • 2 minutes to read • Edit Online
The DebugView property (available only when debugging) provides a string rendering of expression trees. Most of
the syntax is fairly straightforward to understand; the special cases are described in the following sections.
Each example is followed by a block comment, containing the DebugView .
ParameterExpression
System.Linq.Expressions.ParameterExpression variable names are displayed with a $ symbol at the beginning.
If a parameter does not have a name, it is assigned an automatically generated name, such as $var1 or $var2 .
Examples
ConstantExpression
For System.Linq.Expressions.ConstantExpression objects that represent integer values, strings, and null , the value
of the constant is displayed.
For numeric types that have standard suffixes as C# literals, the suffix is added to the value. The following table
shows the suffixes associated with various numeric types.
TYPE K EY W O RD SUF F IX
System.UInt32 uint U
System.Int64 long L
System.UInt64 ulong UL
System.Double double D
System.Single float F
System.Decimal decimal M
Examples
int num = 10;
ConstantExpression expr = Expression.Constant(num);
/*
10
*/
BlockExpression
If the type of a System.Linq.Expressions.BlockExpression object differs from the type of the last expression in the
block, the type is displayed within angle brackets ( < and > ). Otherwise, the type of the BlockExpression object is
not displayed.
Examples
LambdaExpression
System.Linq.Expressions.LambdaExpression objects are displayed together with their delegate types.
If a lambda expression does not have a name, it is assigned an automatically generated name, such as #Lambda1 or
#Lambda2 .
Examples
LabelExpression
If you specify a default value for the System.Linq.Expressions.LabelExpression object, this value is displayed before
the System.Linq.Expressions.LabelTarget object.
The .Label token indicates the start of the label. The .LabelTarget token indicates the destination of the target to
jump to.
If a label does not have a name, it is assigned an automatically generated name, such as #Label1 or #Label2 .
Examples
Checked Operators
Checked operators are displayed with the # symbol in front of the operator. For example, the checked addition
operator is displayed as #+ .
Examples
An iterator can be used to step through collections such as lists and arrays.
An iterator method or get accessor performs a custom iteration over a collection. An iterator method uses the
yield return statement to return each element one at a time. When a yield return statement is reached, the
current location in code is remembered. Execution is restarted from that location the next time the iterator
function is called.
You consume an iterator from client code by using a foreach statement or by using a LINQ query.
In the following example, the first iteration of the foreach loop causes execution to proceed in the SomeNumbers
iterator method until the first yield return statement is reached. This iteration returns a value of 3, and the
current location in the iterator method is retained. On the next iteration of the loop, execution in the iterator
method continues from where it left off, again stopping when it reaches a yield return statement. This iteration
returns a value of 5, and the current location in the iterator method is again retained. The loop completes when
the end of the iterator method is reached.
The return type of an iterator method or get accessor can be IEnumerable, IEnumerable<T>, IEnumerator, or
IEnumerator<T>.
You can use a yield break statement to end the iteration.
NOTE
For all examples in this topic except the Simple Iterator example, include using directives for the System.Collections and
System.Collections.Generic namespaces.
Simple Iterator
The following example has a single yield return statement that is inside a for loop. In Main , each iteration of the
foreach statement body creates a call to the iterator function, which proceeds to the next yield return
statement.
static void Main()
{
foreach (int number in EvenSequence(5, 18))
{
Console.Write(number.ToString() + " ");
}
// Output: 6 8 10 12 14 16 18
Console.ReadKey();
}
The following example creates a Zoo class that contains a collection of animals.
The foreach statement that refers to the class instance ( theZoo ) implicitly calls the GetEnumerator method. The
foreach statements that refer to the Birds and Mammals properties use the AnimalsForType named iterator
method.
static void Main()
{
Zoo theZoo = new Zoo();
theZoo.AddMammal("Whale");
theZoo.AddMammal("Rhinoceros");
theZoo.AddBird("Penguin");
theZoo.AddBird("Warbler");
Console.ReadKey();
}
// Public methods.
public void AddMammal(string name)
{
animals.Add(new Animal { Name = name, Type = Animal.TypeEnum.Mammal });
}
// Public members.
public IEnumerable Mammals
{
get { return AnimalsForType(Animal.TypeEnum.Mammal); }
}
// Private methods.
// Private methods.
private IEnumerable AnimalsForType(Animal.TypeEnum type)
{
foreach (Animal theAnimal in animals)
{
if (theAnimal.Type == type)
{
yield return theAnimal.Name;
}
}
}
// Private class.
private class Animal
{
public enum TypeEnum { Bird, Mammal }
In addition to the generic GetEnumerator method, the non-generic GetEnumerator method must also be
implemented. This is because IEnumerable<T> inherits from IEnumerable. The non-generic implementation
defers to the generic implementation.
The example uses named iterators to support various ways of iterating through the same collection of data. These
named iterators are the TopToBottom and BottomToTop properties, and the TopN method.
The BottomToTop property uses an iterator in a get accessor.
Console.ReadKey();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
Syntax Information
An iterator can occur as a method or get accessor. An iterator cannot occur in an event, instance constructor,
static constructor, or static finalizer.
An implicit conversion must exist from the expression type in the yield return statement to the type argument
for the IEnumerable<T> returned by the iterator.
In C#, an iterator method cannot have any in , ref , or out parameters.
In C#, yield is not a reserved word and has special meaning only when it is used before a return or break
keyword.
Technical Implementation
Although you write an iterator as a method, the compiler translates it into a nested class that is, in effect, a state
machine. This class keeps track of the position of the iterator as long the foreach loop in the client code
continues.
To see what the compiler does, you can use the Ildasm.exe tool to view the Microsoft intermediate language code
that's generated for an iterator method.
When you create an iterator for a class or struct, you don't have to implement the whole IEnumerator interface.
When the compiler detects the iterator, it automatically generates the Current , MoveNext , and Dispose methods
of the IEnumerator or IEnumerator<T> interface.
On each successive iteration of the foreach loop (or the direct call to IEnumerator.MoveNext ), the next iterator
code body resumes after the previous yield return statement. It then continues to the next yield return
statement until the end of the iterator body is reached, or until a yield break statement is encountered.
Iterators don't support the IEnumerator.Reset method. To reiterate from the start, you must obtain a new iterator.
Calling Reset on the iterator returned by an iterator method throws a NotSupportedException.
For additional information, see the C# Language Specification.
Use of Iterators
Iterators enable you to maintain the simplicity of a foreach loop when you need to use complex code to populate
a list sequence. This can be useful when you want to do the following:
Modify the list sequence after the first foreach loop iteration.
Avoid fully loading a large list before the first iteration of a foreach loop. An example is a paged fetch to
load a batch of table rows. Another example is the EnumerateFiles method, which implements iterators in
.NET.
Encapsulate building the list in the iterator. In the iterator method, you can build the list and then yield each
result in a loop.
See also
System.Collections.Generic
IEnumerable<T>
foreach, in
yield
Using foreach with Arrays
Generics
Language Integrated Query (LINQ)
9/3/2020 • 3 minutes to read • Edit Online
Language-Integrated Query (LINQ) is the name for a set of technologies based on the integration of query
capabilities directly into the C# language. Traditionally, queries against data are expressed as simple strings
without type checking at compile time or IntelliSense support. Furthermore, you have to learn a different query
language for each type of data source: SQL databases, XML documents, various Web services, and so on. With
LINQ, a query is a first-class language construct, just like classes, methods, events. You write queries against
strongly typed collections of objects by using language keywords and familiar operators. The LINQ family of
technologies provides a consistent query experience for objects (LINQ to Objects), relational databases (LINQ
to SQL), and XML (LINQ to XML).
For a developer who writes queries, the most visible "language-integrated" part of LINQ is the query
expression. Query expressions are written in a declarative query syntax. By using query syntax, you can
perform filtering, ordering, and grouping operations on data sources with a minimum of code. You use the
same basic query expression patterns to query and transform data in SQL databases, ADO.NET Datasets, XML
documents and streams, and .NET collections.
You can write LINQ queries in C# for SQL Server databases, XML documents, ADO.NET Datasets, and any
collection of objects that supports IEnumerable or the generic IEnumerable<T> interface. LINQ support is also
provided by third parties for many Web services and other database implementations.
The following example shows the complete query operation. The complete operation includes creating a data
source, defining the query expression, and executing the query in a foreach statement.
class LINQQueryExpressions
{
static void Main()
{
The following illustration from Visual Studio shows a partially-completed LINQ query against a SQL Server
database in both C# and Visual Basic with full type checking and IntelliSense support:
Query expression overview
Query expressions can be used to query and to transform data from any LINQ-enabled data source. For
example, a single query can retrieve data from a SQL database, and produce an XML stream as output.
Query expressions are easy to master because they use many familiar C# language constructs.
The variables in a query expression are all strongly typed, although in many cases you do not have to
provide the type explicitly because the compiler can infer it. For more information, see Type relationships in
LINQ query operations.
A query is not executed until you iterate over the query variable, for example, in a foreach statement. For
more information, see Introduction to LINQ queries.
At compile time, query expressions are converted to Standard Query Operator method calls according to
the rules set forth in the C# specification. Any query that can be expressed by using query syntax can also
be expressed by using method syntax. However, in most cases query syntax is more readable and concise.
For more information, see C# language specification and Standard query operators overview.
As a rule when you write LINQ queries, we recommend that you use query syntax whenever possible and
method syntax whenever necessary. There is no semantic or performance difference between the two
different forms. Query expressions are often more readable than equivalent expressions written in method
syntax.
Some query operations, such as Count or Max, have no equivalent query expression clause and must
therefore be expressed as a method call. Method syntax can be combined with query syntax in various ways.
For more information, see Query syntax and method syntax in LINQ.
Query expressions can be compiled to expression trees or to delegates, depending on the type that the
query is applied to. IEnumerable<T> queries are compiled to delegates. IQueryable and IQueryable<T>
queries are compiled to expression trees. For more information, see Expression trees.
Next steps
To learn more details about LINQ, start by becoming familiar with some basic concepts in Query expression
basics, and then read the documentation for the LINQ technology in which you are interested:
XML documents: LINQ to XML
ADO.NET Entity Framework: LINQ to entities
.NET collections, files, strings and so on: LINQ to objects
To gain a deeper understanding of LINQ in general, see LINQ in C#.
To start working with LINQ in C#, see the tutorial Working with LINQ.
Introduction to LINQ Queries (C#)
9/3/2020 • 6 minutes to read • Edit Online
A query is an expression that retrieves data from a data source. Queries are usually expressed in a specialized
query language. Different languages have been developed over time for the various types of data sources, for
example SQL for relational databases and XQuery for XML. Therefore, developers have had to learn a new query
language for each type of data source or data format that they must support. LINQ simplifies this situation by
offering a consistent model for working with data across various kinds of data sources and formats. In a LINQ
query, you are always working with objects. You use the same basic coding patterns to query and transform data
in XML documents, SQL databases, ADO.NET Datasets, .NET collections, and any other format for which a LINQ
provider is available.
class IntroToLINQ
{
static void Main()
{
// The Three Parts of a LINQ Query:
// 1. Data source.
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };
// 2. Query creation.
// numQuery is an IEnumerable<int>
var numQuery =
from num in numbers
where (num % 2) == 0
select num;
// 3. Query execution.
foreach (int num in numQuery)
{
Console.Write("{0,1} ", num);
}
}
}
The following illustration shows the complete query operation. In LINQ, the execution of the query is distinct from
the query itself. In other words, you have not retrieved any data just by creating a query variable.
The Data Source
In the previous example, because the data source is an array, it implicitly supports the generic IEnumerable<T>
interface. This fact means it can be queried with LINQ. A query is executed in a foreach statement, and foreach
requires IEnumerable or IEnumerable<T>. Types that support IEnumerable<T> or a derived interface such as the
generic IQueryable<T> are called queryable types.
A queryable type requires no modification or special treatment to serve as a LINQ data source. If the source data
is not already in memory as a queryable type, the LINQ provider must represent it as such. For example, LINQ to
XML loads an XML document into a queryable XElement type:
With LINQ to SQL, you first create an object-relational mapping at design time either manually or by using the
LINQ to SQL Tools in Visual Studio. You write your queries against the objects, and at run-time LINQ to SQL
handles the communication with the database. In the following example, Customers represents a specific table in
the database, and the type of the query result, IQueryable<T>, derives from IEnumerable<T>.
For more information about how to create specific types of data sources, see the documentation for the various
LINQ providers. However, the basic rule is very simple: a LINQ data source is any object that supports the generic
IEnumerable<T> interface, or an interface that inherits from it.
NOTE
Types such as ArrayList that support the non-generic IEnumerable interface can also be used as a LINQ data source. For
more information, see How to query an ArrayList with LINQ (C#).
The Query
The query specifies what information to retrieve from the data source or sources. Optionally, a query also
specifies how that information should be sorted, grouped, and shaped before it is returned. A query is stored in a
query variable and initialized with a query expression. To make it easier to write queries, C# has introduced new
query syntax.
The query in the previous example returns all the even numbers from the integer array. The query expression
contains three clauses: from , where and select . (If you are familiar with SQL, you will have noticed that the
ordering of the clauses is reversed from the order in SQL.) The from clause specifies the data source, the where
clause applies the filter, and the select clause specifies the type of the returned elements. These and the other
query clauses are discussed in detail in the Language Integrated Query (LINQ) section. For now, the important
point is that in LINQ, the query variable itself takes no action and returns no data. It just stores the information
that is required to produce the results when the query is executed at some later point. For more information
about how queries are constructed behind the scenes, see Standard Query Operators Overview (C#).
NOTE
Queries can also be expressed by using method syntax. For more information, see Query Syntax and Method Syntax in
LINQ.
Query Execution
Deferred Execution
As stated previously, the query variable itself only stores the query commands. The actual execution of the query
is deferred until you iterate over the query variable in a foreach statement. This concept is referred to as
deferred execution and is demonstrated in the following example:
// Query execution.
foreach (int num in numQuery)
{
Console.Write("{0,1} ", num);
}
The foreach statement is also where the query results are retrieved. For example, in the previous query, the
iteration variable num holds each value (one at a time) in the returned sequence.
Because the query variable itself never holds the query results, you can execute it as often as you like. For
example, you may have a database that is being updated continually by a separate application. In your application,
you could create one query that retrieves the latest data, and you could execute it repeatedly at some interval to
retrieve different results every time.
Forcing Immediate Execution
Queries that perform aggregation functions over a range of source elements must first iterate over those
elements. Examples of such queries are Count , Max , Average , and First . These execute without an explicit
foreach statement because the query itself must use foreach in order to return a result. Note also that these
types of queries return a single value, not an IEnumerable collection. The following query returns a count of the
even numbers in the source array:
var evenNumQuery =
from num in numbers
where (num % 2) == 0
select num;
To force immediate execution of any query and cache its results, you can call the ToList or ToArray methods.
List<int> numQuery2 =
(from num in numbers
where (num % 2) == 0
select num).ToList();
// or like this:
// numQuery3 is still an int[]
var numQuery3 =
(from num in numbers
where (num % 2) == 0
select num).ToArray();
You can also force execution by putting the foreach loop immediately after the query expression. However, by
calling ToList or ToArray you also cache all the data in a single collection object.
See also
Getting Started with LINQ in C#
Walkthrough: Writing Queries in C#
Language Integrated Query (LINQ)
foreach, in
Query Keywords (LINQ)
LINQ and Generic Types (C#)
9/3/2020 • 2 minutes to read • Edit Online
LINQ queries are based on generic types, which were introduced in version 2.0 of .NET Framework. You do not
need an in-depth knowledge of generics before you can start writing queries. However, you may want to
understand two basic concepts:
1. When you create an instance of a generic collection class such as List<T>, you replace the "T" with the type
of objects that the list will hold. For example, a list of strings is expressed as List<string> , and a list of
Customer objects is expressed as List<Customer> . A generic list is strongly typed and provides many
benefits over collections that store their elements as Object. If you try to add a Customer to a List<string> ,
you will get an error at compile time. It is easy to use generic collections because you do not have to
perform run-time type-casting.
2. IEnumerable<T> is the interface that enables generic collection classes to be enumerated by using the
foreach statement. Generic collection classes support IEnumerable<T> just as non-generic collection
classes such as ArrayList support IEnumerable.
For more information about generics, see Generics.
IEnumerable<Customer> customerQuery =
from cust in customers
where cust.City == "London"
select cust;
The var keyword is useful when the type of the variable is obvious or when it is not that important to explicitly
specify nested generic types such as those that are produced by group queries. In general, we recommend that if
you use var , realize that it can make your code more difficult for others to read. For more information, see
Implicitly Typed Local Variables.
See also
Generics
Basic LINQ Query Operations (C#)
9/3/2020 • 5 minutes to read • Edit Online
This topic gives a brief introduction to LINQ query expressions and some of the typical kinds of operations that you
perform in a query. More detailed information is in the following topics:
LINQ Query Expressions
Standard Query Operators Overview (C#)
Walkthrough: Writing Queries in C#
NOTE
If you already are familiar with a query language such as SQL or XQuery, you can skip most of this topic. Read about the "
from clause" in the next section to learn about the order of clauses in LINQ query expressions.
//queryAllCustomers is an IEnumerable<Customer>
var queryAllCustomers = from cust in customers
select cust;
The range variable is like the iteration variable in a foreach loop except that no actual iteration occurs in a query
expression. When the query is executed, the range variable will serve as a reference to each successive element in
customers . Because the compiler can infer the type of cust , you do not have to specify it explicitly. Additional
range variables can be introduced by a let clause. For more information, see let clause.
NOTE
For non-generic data sources such as ArrayList, the range variable must be explicitly typed. For more information, see How to
query an ArrayList with LINQ (C#) and from clause.
Filtering
Probably the most common query operation is to apply a filter in the form of a Boolean expression. The filter
causes the query to return only those elements for which the expression is true. The result is produced by using the
where clause. The filter in effect specifies which elements to exclude from the source sequence. In the following
example, only those customers who have an address in London are returned.
You can use the familiar C# logical AND and OR operators to apply as many filter expressions as necessary in the
where clause. For example, to return only customers from "London" AND whose name is "Devon" you would write
the following code:
To return customers from London or Paris, you would write the following code:
Ordering
Often it is convenient to sort the returned data. The orderby clause will cause the elements in the returned
sequence to be sorted according to the default comparer for the type being sorted. For example, the following
query can be extended to sort the results based on the Name property. Because Name is a string, the default
comparer performs an alphabetical sort from A to Z.
var queryLondonCustomers3 =
from cust in customers
where cust.City == "London"
orderby cust.Name ascending
select cust;
To order the results in reverse order, from Z to A, use the orderby…descending clause.
For more information, see orderby clause.
Grouping
The group clause enables you to group your results based on a key that you specify. For example you could specify
that the results should be grouped by the City so that all customers from London or Paris are in individual
groups. In this case, cust.City is the key.
When you end a query with a group clause, your results take the form of a list of lists. Each element in the list is an
object that has a Key member and a list of elements that are grouped under that key. When you iterate over a
query that produces a sequence of groups, you must use a nested foreach loop. The outer loop iterates over each
group, and the inner loop iterates over each group's members.
If you must refer to the results of a group operation, you can use the into keyword to create an identifier that can
be queried further. The following query returns only those groups that contain more than two customers:
Joining
Join operations create associations between sequences that are not explicitly modeled in the data sources. For
example you can perform a join to find all the customers and distributors who have the same location. In LINQ the
join clause always works against object collections instead of database tables directly.
var innerJoinQuery =
from cust in customers
join dist in distributors on cust.City equals dist.City
select new { CustomerName = cust.Name, DistributorName = dist.Name };
In LINQ, you do not have to use join as often as you do in SQL, because foreign keys in LINQ are represented in
the object model as properties that hold a collection of items. For example, a Customer object contains a collection
of Order objects. Rather than performing a join, you access the orders by using dot notation:
Selecting (Projections)
The select clause produces the results of the query and specifies the "shape" or type of each returned element.
For example, you can specify whether your results will consist of complete Customer objects, just one member, a
subset of members, or some completely different result type based on a computation or new object creation. When
the select clause produces something other than a copy of the source element, the operation is called a
projection. The use of projections to transform data is a powerful capability of LINQ query expressions. For more
information, see Data Transformations with LINQ (C#) and select clause.
See also
LINQ Query Expressions
Walkthrough: Writing Queries in C#
Query Keywords (LINQ)
Anonymous Types
Data Transformations with LINQ (C#)
9/3/2020 • 6 minutes to read • Edit Online
Language-Integrated Query (LINQ) is not only about retrieving data. It is also a powerful tool for transforming
data. By using a LINQ query, you can use a source sequence as input and modify it in many ways to create a new
output sequence. You can modify the sequence itself without modifying the elements themselves by sorting and
grouping. But perhaps the most powerful feature of LINQ queries is the ability to create new types. This is
accomplished in the select clause. For example, you can perform the following tasks:
Merge multiple input sequences into a single output sequence that has a new type.
Create output sequences whose elements consist of only one or several properties of each element in the
source sequence.
Create output sequences whose elements consist of the results of operations performed on the source data.
Create output sequences in a different format. For example, you can transform data from SQL rows or text
files into XML.
These are just several examples. Of course, these transformations can be combined in various ways in the same
query. Furthermore, the output sequence of one query can be used as the input sequence for a new query.
class Student
{
public string First { get; set; }
public string Last {get; set;}
public int ID { get; set; }
public string Street { get; set; }
public string City { get; set; }
public List<int> Scores;
}
class Teacher
{
public string First { get; set; }
public string Last { get; set; }
public int ID { get; set; }
public string City { get; set; }
}
2. To create elements that contain more than one property from the source element, you can use an object
initializer with either a named object or an anonymous type. The following example shows the use of an
anonymous type to encapsulate two properties from each Customer element:
For more information, see Object and Collection Initializers and Anonymous Types.
class XMLTransform
{
static void Main()
{
// Create the data source by using a collection initializer.
// The Student class was defined previously in this topic.
List<Student> students = new List<Student>()
{
new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores = new List<int>{97, 92, 81, 60}},
new Student {First="Claire", Last="O’Donnell", ID=112, Scores = new List<int>{75, 84, 91, 39}},
new Student {First="Sven", Last="Mortensen", ID=113, Scores = new List<int>{88, 94, 65, 91}},
};
NOTE
Calling methods in query expressions is not supported if the query will be translated into some other domain. For example,
you cannot call an ordinary C# method in LINQ to SQL because SQL Server has no context for it. However, you can map
stored procedures to methods and call those. For more information, see Stored Procedures.
class FormatQuery
{
static void Main()
{
// Data source.
double[] radii = { 1, 2, 3 };
/*
// LINQ query using query syntax.
IEnumerable<string> output =
from rad in radii
select $"Area for a circle with a radius of '{rad}' = {rad * rad * Math.PI:F2}";
*/
See also
Language-Integrated Query (LINQ) (C#)
LINQ to SQL
LINQ to DataSet
LINQ to XML (C#)
LINQ Query Expressions
select clause
Type Relationships in LINQ Query Operations (C#)
9/3/2020 • 2 minutes to read • Edit Online
To write queries effectively, you should understand how types of the variables in a complete query operation all
relate to each other. If you understand these relationships you will more easily comprehend the LINQ samples
and code examples in the documentation. Furthermore, you will understand what occurs behind the scenes when
variables are implicitly typed by using var .
LINQ query operations are strongly typed in the data source, in the query itself, and in the query execution. The
type of the variables in the query must be compatible with the type of the elements in the data source and with
the type of the iteration variable in the foreach statement. This strong typing guarantees that type errors are
caught at compile time when they can be corrected before users encounter them.
In order to demonstrate these type relationships, most of the examples that follow use explicit typing for all
variables. The last example shows how the same principles apply even when you use implicit typing by using var.
1. The type argument of the data source determines the type of the range variable.
2. The type of the object that is selected determines the type of the query variable. Here name is a string.
Therefore, the query variable is an IEnumerable<string> .
3. The query variable is iterated over in the foreach statement. Because the query variable is a sequence of
strings, the iteration variable is also a string.
The following illustration shows a slightly more complex transformation. The select statement returns an
anonymous type that captures just two members of the original Customer object.
1. The type argument of the data source is always the type of the range variable in the query.
2. Because the select statement produces an anonymous type, the query variable must be implicitly typed
by using var .
3. Because the type of the query variable is implicit, the iteration variable in the foreach loop must also be
implicit.
Most queries in the introductory Language Integrated Query (LINQ) documentation are written by using the
LINQ declarative query syntax. However, the query syntax must be translated into method calls for the .NET
common language runtime (CLR) when the code is compiled. These method calls invoke the standard query
operators, which have names such as Where , Select , GroupBy , Join , Max , and Average . You can call them
directly by using method syntax instead of query syntax.
Query syntax and method syntax are semantically identical, but many people find query syntax simpler and
easier to read. Some queries must be expressed as method calls. For example, you must use a method call to
express a query that retrieves the number of elements that match a specified condition. You also must use a
method call for a query that retrieves the element that has the maximum value in a source sequence. The
reference documentation for the standard query operators in the System.Linq namespace generally uses method
syntax. Therefore, even when getting started writing LINQ queries, it is useful to be familiar with how to use
method syntax in queries and in query expressions themselves.
//Query syntax:
IEnumerable<int> numQuery1 =
from num in numbers
where num % 2 == 0
orderby num
select num;
//Method syntax:
IEnumerable<int> numQuery2 = numbers.Where(num => num % 2 == 0).OrderBy(n => n);
The output from the two examples is identical. You can see that the type of the query variable is the same in both
forms: IEnumerable<T>.
To understand the method-based query, let's examine it more closely. On the right side of the expression, notice
that the where clause is now expressed as an instance method on the numbers object, which as you will recall
has a type of IEnumerable<int> . If you are familiar with the generic IEnumerable<T> interface, you know that it
does not have a Where method. However, if you invoke the IntelliSense completion list in the Visual Studio IDE,
you will see not only a Where method, but many other methods such as Select , SelectMany , Join , and
Orderby . These are all the standard query operators.
Although it looks as if IEnumerable<T> has been redefined to include these additional methods, in fact this is not
the case. The standard query operators are implemented as a new kind of method called extension methods.
Extensions methods "extend" an existing type; they can be called as if they were instance methods on the type.
The standard query operators extend IEnumerable<T> and that is why you can write numbers.Where(...) .
To get started using LINQ, all that you really have to know about extension methods is how to bring them into
scope in your application by using the correct using directives. From your application's point of view, an
extension method and a regular instance method are the same.
For more information about extension methods, see Extension Methods. For more information about standard
query operators, see Standard Query Operators Overview (C#). Some LINQ providers, such as LINQ to SQL and
LINQ to XML, implement their own standard query operators and additional extension methods for other types
besides IEnumerable<T>.
Lambda Expressions
In the previous example, notice that the conditional expression ( num % 2 == 0 ) is passed as an in-line argument
to the Where method: Where(num => num % 2 == 0). This inline expression is called a lambda expression. It is a
convenient way to write code that would otherwise have to be written in more cumbersome form as an
anonymous method or a generic delegate or an expression tree. In C# => is the lambda operator, which is read
as "goes to". The num on the left of the operator is the input variable which corresponds to num in the query
expression. The compiler can infer the type of num because it knows that numbers is a generic IEnumerable<T>
type. The body of the lambda is just the same as the expression in query syntax or in any other C# expression or
statement; it can include method calls and other complex logic. The "return value" is just the expression result.
To get started using LINQ, you do not have to use lambdas extensively. However, certain queries can only be
expressed in method syntax and some of those require lambda expressions. After you become more familiar with
lambdas, you will find that they are a powerful and flexible tool in your LINQ toolbox. For more information, see
Lambda Expressions.
Composability of Queries
In the previous code example, note that the OrderBy method is invoked by using the dot operator on the call to
Where . Where produces a filtered sequence, and then Orderby operates on that sequence by sorting it. Because
queries return an IEnumerable , you compose them in method syntax by chaining the method calls together. This
is what the compiler does behind the scenes when you write queries by using query syntax. And because a query
variable does not store the results of the query, you can modify it or use it as the basis for a new query at any
time, even after it has been executed.
C# Features That Support LINQ
9/3/2020 • 3 minutes to read • Edit Online
The following section introduces new language constructs introduced in C# 3.0. Although these new features are
all used to a degree with LINQ queries, they are not limited to LINQ and can be used in any context where you find
them useful.
Query Expressions
Query expressions use a declarative syntax similar to SQL or XQuery to query over IEnumerable collections. At
compile time query syntax is converted to method calls to a LINQ provider's implementation of the standard query
operator extension methods. Applications control the standard query operators that are in scope by specifying the
appropriate namespace with a using directive. The following query expression takes an array of strings, groups
them according to the first character in the string, and orders the groups.
var number = 5;
var name = "Virginia";
var query = from str in stringArray
where str[0] == 'm'
select str;
Variables declared as var are just as strongly typed as variables whose type you specify explicitly. The use of var
makes it possible to create anonymous types, but it can be used only for local variables. Arrays can also be
declared with implicit typing.
For more information, see Implicitly Typed Local Variables.
Continuing with our Customer class, assume that there is a data source called IncomingOrders , and that for each
order with a large OrderSize , we would like to create a new Customer based off of that order. A LINQ query can be
executed on this data source and use object initialization to fill a collection:
The data source may have more properties lying under the hood than the Customer class such as OrderSize , but
with object initialization, the data returned from the query is molded into the desired data type; we choose the data
that is relevant to our class. As a result, we now have an IEnumerable filled with the new Customer s we wanted.
The above can also be written in LINQ's method syntax:
var newLargeOrderCustomers = IncomingOrders.Where(x => x.OrderSize > 5).Select(y => new Customer { Name =
y.Name, Phone = y.Phone });
Anonymous Types
An anonymous type is constructed by the compiler and the type name is only available to the compiler.
Anonymous types provide a convenient way to group a set of properties temporarily in a query result without
having to define a separate named type. Anonymous types are initialized with a new expression and an object
initializer, as shown here:
Extension Methods
An extension method is a static method that can be associated with a type, so that it can be called as if it were an
instance method on the type. This feature enables you to, in effect, "add" new methods to existing types without
actually modifying them. The standard query operators are a set of extension methods that provide LINQ query
functionality for any type that implements IEnumerable<T>.
For more information, see Extension Methods.
Lambda Expressions
A lambda expression is an inline function that uses the => operator to separate input parameters from the
function body and can be converted at compile time to a delegate or an expression tree. In LINQ programming,
you will encounter lambda expressions when you make direct method calls to the standard query operators.
For more information, see:
Anonymous Functions
Lambda Expressions
Expression Trees (C#)
See also
Language-Integrated Query (LINQ) (C#)
Walkthrough: Writing Queries in C# (LINQ)
9/3/2020 • 10 minutes to read • Edit Online
This walkthrough demonstrates the C# language features that are used to write LINQ query expressions.
Create a C# Project
NOTE
The following instructions are for Visual Studio. If you are using a different development environment, create a console
project with a reference to System.Core.dll and a using directive for the System.Linq namespace.
// Output:
// Omelchenko, Svetlana
// Garcia, Cesar
// Fakhouri, Fadi
// Feng, Hanying
// Garcia, Hugo
// Adams, Terry
// Zabokritski, Eugene
// Tucker, Michael
2. Now change the orderby clause so that it orders the results in reverse order according to the score on the
first test, from the highest score to the lowest score.
3. Change the WriteLine format string so that you can see the scores:
2. Note that the type of the query has now changed. It now produces a sequence of groups that have a char
type as a key, and a sequence of Student objects. Because the type of the query has changed, the following
code changes the foreach execution loop also:
// Output:
// O
// Omelchenko, Svetlana
// O'Donnell, Claire
// M
// Mortensen, Sven
// G
// Garcia, Cesar
// Garcia, Debra
// Garcia, Hugo
// F
// Fakhouri, Fadi
// Feng, Hanying
// T
// Tucker, Lance
// Tucker, Michael
// A
// Adams, Terry
// Z
// Zabokritski, Eugene
3. Run the application and view the results in the Console window.
For more information, see group clause.
To make the variables implicitly typed
1. Explicitly coding IEnumerables of IGroupings can quickly become tedious. You can write the same query
and foreach loop much more conveniently by using var . The var keyword does not change the types of
your objects; it just instructs the compiler to infer the types. Change the type of studentQuery and the
iteration variable group to var and rerun the query. Note that in the inner foreach loop, the iteration
variable is still typed as Student , and the query works just as before. Change the s iteration variable to
var and run the query again. You see that you get exactly the same results.
var studentQuery3 =
from student in students
group student by student.Last[0];
// Output:
// O
// Omelchenko, Svetlana
// O'Donnell, Claire
// M
// Mortensen, Sven
// G
// Garcia, Cesar
// Garcia, Debra
// Garcia, Hugo
// F
// Fakhouri, Fadi
// Feng, Hanying
// T
// Tucker, Lance
// Tucker, Michael
// A
// Adams, Terry
// Z
// Zabokritski, Eugene
For more information about var, see Implicitly Typed Local Variables.
To order the groups by their key value
1. When you run the previous query, you notice that the groups are not in alphabetical order. To change this,
you must provide an orderby clause after the group clause. But to use an orderby clause, you first need
an identifier that serves as a reference to the groups created by the group clause. You provide the identifier
by using the into keyword, as follows:
var studentQuery4 =
from student in students
group student by student.Last[0] into studentGroup
orderby studentGroup.Key
select studentGroup;
// Output:
//A
// Adams, Terry
//F
// Fakhouri, Fadi
// Feng, Hanying
//G
// Garcia, Cesar
// Garcia, Debra
// Garcia, Hugo
//M
// Mortensen, Sven
//O
// Omelchenko, Svetlana
// O'Donnell, Claire
//T
// Tucker, Lance
// Tucker, Michael
//Z
// Zabokritski, Eugene
When you run this query, you will see the groups are now sorted in alphabetical order.
To introduce an identifier by using let
1. You can use the let keyword to introduce an identifier for any expression result in the query expression.
This identifier can be a convenience, as in the following example, or it can enhance performance by storing
the results of an expression so that it does not have to be calculated multiple times.
// studentQuery5 is an IEnumerable<string>
// This query returns those students whose
// first test score was higher than their
// average score.
var studentQuery5 =
from student in students
let totalScore = student.Scores[0] + student.Scores[1] +
student.Scores[2] + student.Scores[3]
where totalScore / 4 < student.Scores[0]
select student.Last + " " + student.First;
// Output:
// Omelchenko Svetlana
// O'Donnell Claire
// Mortensen Sven
// Garcia Cesar
// Fakhouri Fadi
// Feng Hanying
// Garcia Hugo
// Adams Terry
// Zabokritski Eugene
// Tucker Michael
var studentQuery6 =
from student in students
let totalScore = student.Scores[0] + student.Scores[1] +
student.Scores[2] + student.Scores[3]
select totalScore;
// Output:
// Class average score = 334.166666666667
// Output:
// The Garcias in the class are:
// Cesar
// Debra
// Hugo
2. Code earlier in this walkthrough indicated that the average class score is approximately 334. To produce a
sequence of Students whose total score is greater than the class average, together with their Student ID ,
you can use an anonymous type in the select statement:
var studentQuery8 =
from student in students
let x = student.Scores[0] + student.Scores[1] +
student.Scores[2] + student.Scores[3]
where x > averageScore
select new { id = student.ID, score = x };
// Output:
// Student ID: 113, Score: 338
// Student ID: 114, Score: 353
// Student ID: 116, Score: 369
// Student ID: 117, Score: 352
// Student ID: 118, Score: 343
// Student ID: 120, Score: 341
// Student ID: 122, Score: 368
Next Steps
After you are familiar with the basic aspects of working with queries in C#, you are ready to read the
documentation and samples for the specific type of LINQ provider you are interested in:
LINQ to SQL
LINQ to DataSet
LINQ to XML (C#)
LINQ to Objects (C#)
See also
Language-Integrated Query (LINQ) (C#)
LINQ Query Expressions
Standard Query Operators Overview (C#)
9/3/2020 • 3 minutes to read • Edit Online
The standard query operators are the methods that form the LINQ pattern. Most of these methods operate on
sequences, where a sequence is an object whose type implements the IEnumerable<T> interface or the
IQueryable<T> interface. The standard query operators provide query capabilities including filtering,
projection, aggregation, sorting and more.
There are two sets of LINQ standard query operators: one that operates on objects of type IEnumerable<T>,
another that operates on objects of type IQueryable<T>. The methods that make up each set are static
members of the Enumerable and Queryable classes, respectively. They are defined as extension methods of
the type that they operate on. Extension methods can be called by using either static method syntax or
instance method syntax.
In addition, several standard query operator methods operate on types other than those based on
IEnumerable<T> or IQueryable<T>. The Enumerable type defines two such methods that both operate on
objects of type IEnumerable. These methods, Cast<TResult>(IEnumerable) and OfType<TResult>
(IEnumerable), let you enable a non-parameterized, or non-generic, collection to be queried in the LINQ
pattern. They do this by creating a strongly typed collection of objects. The Queryable class defines two similar
methods, Cast<TResult>(IQueryable) and OfType<TResult>(IQueryable), that operate on objects of type
Queryable.
The standard query operators differ in the timing of their execution, depending on whether they return a
singleton value or a sequence of values. Those methods that return a singleton value (for example, Average
and Sum) execute immediately. Methods that return a sequence defer the query execution and return an
enumerable object.
For methods that operate on in-memory collections, that is, those methods that extend IEnumerable<T>, the
returned enumerable object captures the arguments that were passed to the method. When that object is
enumerated, the logic of the query operator is employed and the query results are returned.
In contrast, methods that extend IQueryable<T> don't implement any querying behavior. They build an
expression tree that represents the query to be performed. The query processing is handled by the source
IQueryable<T> object.
Calls to query methods can be chained together in one query, which enables queries to become arbitrarily
complex.
The following code example demonstrates how the standard query operators can be used to obtain
information about a sequence.
string sentence = "the quick brown fox jumps over the lazy dog";
// Split the string into individual words to create a collection.
string[] words = sentence.Split(' ');
Related Sections
The following links take you to articles that provide additional information about the various standard query
operators based on functionality.
Sorting Data (C#)
Set Operations (C#)
Filtering Data (C#)
Quantifier Operations (C#)
Projection Operations (C#)
Partitioning Data (C#)
Join Operations (C#)
Grouping Data (C#)
Generation Operations (C#)
Equality Operations (C#)
Element Operations (C#)
Converting Data Types (C#)
Concatenation Operations (C#)
Aggregation Operations (C#)
See also
Enumerable
Queryable
Introduction to LINQ Queries (C#)
Query Expression Syntax for Standard Query Operators (C#)
Classification of Standard Query Operators by Manner of Execution (C#)
Extension Methods
Query Expression Syntax for Standard Query
Operators (C#)
9/3/2020 • 2 minutes to read • Edit Online
Some of the more frequently used standard query operators have dedicated C# language keyword syntax that
enables them to be called as part of a query expression. A query expression is a different, more readable form of
expressing a query than its method-based equivalent. Query expression clauses are translated into calls to the
query methods at compile time.
GroupBy group … by
-or-
group … by … into …
OrderBy<TSource,TKey>(IEnumerable<TSource>, orderby
Func<TSource,TKey>)
(For more information, see orderby clause.)
Select select
ThenBy<TSource,TKey>(IOrderedEnumerable<TSource>, orderby …, …
Func<TSource,TKey>)
(For more information, see orderby clause.)
Where where
See also
Enumerable
Queryable
Standard Query Operators Overview (C#)
Classification of Standard Query Operators by Manner of Execution (C#)
Classification of Standard Query Operators by
Manner of Execution (C#)
9/3/2020 • 3 minutes to read • Edit Online
The LINQ to Objects implementations of the standard query operator methods execute in one of two main ways:
immediate or deferred. The query operators that use deferred execution can be additionally divided into two
categories: streaming and non-streaming. If you know how the different query operators execute, it may help you
understand the results that you get from a given query. This is especially true if the data source is changing or if
you are building a query on top of another query. This topic classifies the standard query operators according to
their manner of execution.
Manners of Execution
Immediate
Immediate execution means that the data source is read and the operation is performed at the point in the code
where the query is declared. All the standard query operators that return a single, non-enumerable result execute
immediately.
Deferred
Deferred execution means that the operation is not performed at the point in the code where the query is declared.
The operation is performed only when the query variable is enumerated, for example by using a foreach
statement. This means that the results of executing the query depend on the contents of the data source when the
query is executed rather than when the query is defined. If the query variable is enumerated multiple times, the
results might differ every time. Almost all the standard query operators whose return type is IEnumerable<T> or
IOrderedEnumerable<TElement> execute in a deferred manner.
Query operators that use deferred execution can be additionally classified as streaming or non-streaming.
Streaming
Streaming operators do not have to read all the source data before they yield elements. At the time of execution, a
streaming operator performs its operation on each source element as it is read and yields the element if
appropriate. A streaming operator continues to read source elements until a result element can be produced. This
means that more than one source element might be read to produce one result element.
Non-Streaming
Non-streaming operators must read all the source data before they can yield a result element. Operations such as
sorting or grouping fall into this category. At the time of execution, non-streaming query operators read all the
source data, put it into a data structure, perform the operation, and yield the resulting elements.
Classification Table
The following table classifies each standard query operator method according to its method of execution.
NOTE
If an operator is marked in two columns, two input sequences are involved in the operation, and each sequence is evaluated
differently. In these cases, it is always the first sequence in the parameter list that is evaluated in a deferred, streaming
manner.
DEF ERRED DEF ERRED N O N -
STA N DA RD Q UERY IM M EDIAT E ST REA M IN G ST REA M IN G
O P ERATO R RET URN T Y P E EXEC UT IO N EXEC UT IO N EXEC UT IO N
Aggregate TSource X
All Boolean X
Any Boolean X
AsEnumerable IEnumerable<T> X
Cast IEnumerable<T> X
Concat IEnumerable<T> X
Contains Boolean X
Count Int32 X
DefaultIfEmpty IEnumerable<T> X
Distinct IEnumerable<T> X
ElementAt TSource X
ElementAtOrDefault TSource X
Empty IEnumerable<T> X
Except IEnumerable<T> X X
First TSource X
FirstOrDefault TSource X
GroupBy IEnumerable<T> X
GroupJoin IEnumerable<T> X X
Intersect IEnumerable<T> X X
Join IEnumerable<T> X X
Last TSource X
LastOrDefault TSource X
LongCount Int64 X
DEF ERRED DEF ERRED N O N -
STA N DA RD Q UERY IM M EDIAT E ST REA M IN G ST REA M IN G
O P ERATO R RET URN T Y P E EXEC UT IO N EXEC UT IO N EXEC UT IO N
OfType IEnumerable<T> X
OrderBy IOrderedEnumerable X
<TElement>
OrderByDescending IOrderedEnumerable X
<TElement>
Range IEnumerable<T> X
Repeat IEnumerable<T> X
Reverse IEnumerable<T> X
Select IEnumerable<T> X
SelectMany IEnumerable<T> X
SequenceEqual Boolean X
Single TSource X
SingleOrDefault TSource X
Skip IEnumerable<T> X
SkipWhile IEnumerable<T> X
Take IEnumerable<T> X
TakeWhile IEnumerable<T> X
ThenBy IOrderedEnumerable X
<TElement>
ThenByDescending IOrderedEnumerable X
<TElement>
ToDictionary Dictionary<TKey,TVal X
ue>
DEF ERRED DEF ERRED N O N -
STA N DA RD Q UERY IM M EDIAT E ST REA M IN G ST REA M IN G
O P ERATO R RET URN T Y P E EXEC UT IO N EXEC UT IO N EXEC UT IO N
ToList IList<T> X
ToLookup ILookup<TKey,TEleme X
nt>
Union IEnumerable<T> X
Where IEnumerable<T> X
See also
Enumerable
Standard Query Operators Overview (C#)
Query Expression Syntax for Standard Query Operators (C#)
LINQ to Objects (C#)
Sorting Data (C#)
9/3/2020 • 2 minutes to read • Edit Online
A sorting operation orders the elements of a sequence based on one or more attributes. The first sort criterion
performs a primary sort on the elements. By specifying a second sort criterion, you can sort the elements within
each primary sort group.
The following illustration shows the results of an alphabetical sort operation on a sequence of characters:
The standard query operator methods that sort data are listed in the following section.
Methods
C # Q UERY EXP RESSIO N
M ET H O D N A M E DESC RIP T IO N SY N TA X M O RE IN F O RM AT IO N
Queryable.OrderByDescendi
ng
Queryable.ThenByDescendin
g
the
fox
quick
brown
jumps
*/
the
quick
jumps
fox
brown
*/
fox
the
brown
jumps
quick
*/
the
fox
quick
jumps
brown
*/
See also
System.Linq
Standard Query Operators Overview (C#)
orderby clause
Order the results of a join clause
How to sort or filter text data by any word or field (LINQ) (C#)
Set Operations (C#)
9/3/2020 • 2 minutes to read • Edit Online
Set operations in LINQ refer to query operations that produce a result set that is based on the presence or absence
of equivalent elements within the same or separate collections (or sets).
The standard query operator methods that perform set operations are listed in the following section.
Methods
C # Q UERY EXP RESSIO N
M ET H O D N A M E DESC RIP T IO N SY N TA X M O RE IN F O RM AT IO N
Except
The following example depicts the behavior of Enumerable.Except. The returned sequence contains only the
elements from the first input sequence that are not in the second input sequence.
Intersect
The following example depicts the behavior of Enumerable.Intersect. The returned sequence contains the elements
that are common to both of the input sequences.
string[] planets1 = { "Mercury", "Venus", "Earth", "Jupiter" };
string[] planets2 = { "Mercury", "Earth", "Mars", "Jupiter" };
Union
The following example depicts a union operation on two sequences of characters. The returned sequence contains
the unique elements from both input sequences.
See also
System.Linq
Standard Query Operators Overview (C#)
How to combine and compare string collections (LINQ) (C#)
How to find the set difference between two lists (LINQ) (C#)
Filtering Data (C#)
9/3/2020 • 2 minutes to read • Edit Online
Filtering refers to the operation of restricting the result set to contain only those elements that satisfy a specified
condition. It is also known as selection.
The following illustration shows the results of filtering a sequence of characters. The predicate for the filtering
operation specifies that the character must be 'A'.
The standard query operator methods that perform selection are listed in the following section.
Methods
C # Q UERY EXP RESSIO N
M ET H O D N A M E DESC RIP T IO N SY N TA X M O RE IN F O RM AT IO N
the
fox
*/
See also
System.Linq
Standard Query Operators Overview (C#)
where clause
Dynamically specify predicate filters at runtime
How to query an assembly's metadata with Reflection (LINQ) (C#)
How to query for files with a specified attribute or name (C#)
How to sort or filter text data by any word or field (LINQ) (C#)
Quantifier Operations (C#)
9/3/2020 • 2 minutes to read • Edit Online
Quantifier operations return a Boolean value that indicates whether some or all of the elements in a sequence
satisfy a condition.
The following illustration depicts two different quantifier operations on two different source sequences. The first
operation asks if one or more of the elements are the character 'A', and the result is true . The second operation
asks if all the elements are the character 'A', and the result is true .
The standard query operator methods that perform quantifier operations are listed in the following section.
Methods
C # Q UERY EXP RESSIO N
M ET H O D N A M E DESC RIP T IO N SY N TA X M O RE IN F O RM AT IO N
Any
The following example uses the Any to check that any strings are start with 'o'.
class Market
{
public string Name { get; set; }
public string[] Items { get; set; }
}
// Determine which market have any fruit names start with 'o'
IEnumerable<string> names = from market in markets
where market.Items.Any(item => item.StartsWith("o"))
select market.Name;
class Market
{
public string Name { get; set; }
public string[] Items { get; set; }
}
See also
System.Linq
Standard Query Operators Overview (C#)
Dynamically specify predicate filters at runtime
How to query for sentences that contain a specified set of words (LINQ) (C#)
Projection Operations (C#)
9/3/2020 • 3 minutes to read • Edit Online
Projection refers to the operation of transforming an object into a new form that often consists only of those
properties that will be subsequently used. By using projection, you can construct a new type that is built from each
object. You can project a property and perform a mathematical function on it. You can also project the original
object without changing it.
The standard query operator methods that perform projection are listed in the following section.
Methods
C # Q UERY EXP RESSIO N
M ET H O D N A M E DESC RIP T IO N SY N TA X M O RE IN F O RM AT IO N
a
a
a
d
*/
SelectMany
The following example uses multiple from clauses to project each word from each string in a list of strings.
List<string> phrases = new List<string>() { "an apple a day", "the quick brown fox" };
an
apple
a
day
the
quick
brown
fox
*/
This illustration depicts how SelectMany() concatenates the intermediate sequence of arrays into one final result
value that contains each value from each intermediate array.
Code Example
The following example compares the behavior of Select() and SelectMany() . The code creates a "bouquet" of
flowers by taking the first two items from each list of flower names in the source collection. In this example, the
"single value" that the transform function Select<TSource,TResult>(IEnumerable<TSource>,
Func<TSource,TResult>) uses is itself a collection of values. This requires the extra foreach loop in order to
enumerate each string in each sub-sequence.
class Bouquet
{
public List<string> Flowers { get; set; }
}
See also
System.Linq
Standard Query Operators Overview (C#)
select clause
How to populate object collections from multiple sources (LINQ) (C#)
How to split a file into many files by using groups (LINQ) (C#)
Partitioning Data (C#)
9/3/2020 • 2 minutes to read • Edit Online
Partitioning in LINQ refers to the operation of dividing an input sequence into two sections, without rearranging
the elements, and then returning one of the sections.
The following illustration shows the results of three different partitioning operations on a sequence of characters.
The first operation returns the first three elements in the sequence. The second operation skips the first three
elements and returns the remaining elements. The third operation skips the first two elements in the sequence and
returns the next three elements.
The standard query operator methods that partition sequences are listed in the following section.
Operators
C # Q UERY EXP RESSIO N
O P ERATO R N A M E DESC RIP T IO N SY N TA X M O RE IN F O RM AT IO N
See also
System.Linq
Standard Query Operators Overview (C#)
Join Operations (C#)
9/3/2020 • 4 minutes to read • Edit Online
A join of two data sources is the association of objects in one data source with objects that share a common
attribute in another data source.
Joining is an important operation in queries that target data sources whose relationships to each other cannot be
followed directly. In object-oriented programming, this could mean a correlation between objects that is not
modeled, such as the backwards direction of a one-way relationship. An example of a one-way relationship is a
Customer class that has a property of type City, but the City class does not have a property that is a collection of
Customer objects. If you have a list of City objects and you want to find all the customers in each city, you could
use a join operation to find them.
The join methods provided in the LINQ framework are Join and GroupJoin. These methods perform equijoins, or
joins that match two data sources based on equality of their keys. (For comparison, Transact-SQL supports join
operators other than 'equals', for example the 'less than' operator.) In relational database terms, Join implements
an inner join, a type of join in which only those objects that have a match in the other data set are returned. The
GroupJoin method has no direct equivalent in relational database terms, but it implements a superset of inner
joins and left outer joins. A left outer join is a join that returns each element of the first (left) data source, even if it
has no correlated elements in the other data source.
The following illustration shows a conceptual view of two sets and the elements within those sets that are included
in either an inner join or a left outer join.
Methods
C # Q UERY EXP RESSIO N
M ET H O D N A M E DESC RIP T IO N SY N TA X M O RE IN F O RM AT IO N
class Category
{
public int Id { get; set; }
public string CategoryName { get; set; }
}
GroupJoin
The following example uses the join … in … on … equals … into … clause to join two sequences based on specific
value and groups the resulting matches for each element:
class Product
{
public string Name { get; set; }
public int CategoryId { get; set; }
}
class Category
{
public int Id { get; set; }
public string CategoryName { get; set; }
}
See also
System.Linq
Standard Query Operators Overview (C#)
Anonymous Types
Formulate Joins and Cross-Product Queries
join clause
Join by using composite keys
How to join content from dissimilar files (LINQ) (C#)
Order the results of a join clause
Perform custom join operations
Perform grouped joins
Perform inner joins
Perform left outer joins
How to populate object collections from multiple sources (LINQ) (C#)
Grouping Data (C#)
9/3/2020 • 2 minutes to read • Edit Online
Grouping refers to the operation of putting data into groups so that the elements in each group share a common
attribute.
The following illustration shows the results of grouping a sequence of characters. The key for each group is the
character.
The standard query operator methods that group data elements are listed in the following section.
Methods
C # Q UERY EXP RESSIO N
M ET H O D N A M E DESC RIP T IO N SY N TA X M O RE IN F O RM AT IO N
Odd numbers:
35
3987
199
329
Even numbers:
44
200
84
4
446
208
*/
See also
System.Linq
Standard Query Operators Overview (C#)
group clause
Create a nested group
How to group files by extension (LINQ) (C#)
Group query results
Perform a subquery on a grouping operation
How to split a file into many files by using groups (LINQ) (C#)
Generation Operations (C#)
9/3/2020 • 2 minutes to read • Edit Online
Methods
C # Q UERY EXP RESSIO N
M ET H O D N A M E DESC RIP T IO N SY N TA X M O RE IN F O RM AT IO N
See also
System.Linq
Standard Query Operators Overview (C#)
Equality Operations (C#)
9/3/2020 • 2 minutes to read • Edit Online
Two sequences whose corresponding elements are equal and which have the same number of elements are
considered equal.
Methods
C # Q UERY EXP RESSIO N
M ET H O D N A M E DESC RIP T IO N SY N TA X M O RE IN F O RM AT IO N
See also
System.Linq
Standard Query Operators Overview (C#)
How to compare the contents of two folders (LINQ) (C#)
Element Operations (C#)
9/3/2020 • 2 minutes to read • Edit Online
Methods
C # Q UERY EXP RESSIO N
M ET H O D N A M E DESC RIP T IO N SY N TA X M O RE IN F O RM AT IO N
See also
System.Linq
Standard Query Operators Overview (C#)
How to query for the largest file or files in a directory tree (LINQ) (C#)
Converting Data Types (C#)
9/3/2020 • 2 minutes to read • Edit Online
Methods
The following table lists the standard query operator methods that perform data-type conversions.
The conversion methods in this table whose names start with "As" change the static type of the source collection
but do not enumerate it. The methods whose names start with "To" enumerate the source collection and put the
items into the corresponding collection type.
class Plant
{
public string Name { get; set; }
}
See also
System.Linq
Standard Query Operators Overview (C#)
from clause
LINQ Query Expressions
How to query an ArrayList with LINQ (C#)
Concatenation Operations (C#)
9/3/2020 • 2 minutes to read • Edit Online
The standard query operator methods that perform concatenation are listed in the following section.
Methods
C # Q UERY EXP RESSIO N
M ET H O D N A M E DESC RIP T IO N SY N TA X M O RE IN F O RM AT IO N
See also
System.Linq
Standard Query Operators Overview (C#)
How to combine and compare string collections (LINQ) (C#)
Aggregation Operations (C#)
9/3/2020 • 2 minutes to read • Edit Online
An aggregation operation computes a single value from a collection of values. An example of an aggregation
operation is calculating the average daily temperature from a month's worth of daily temperature values.
The following illustration shows the results of two different aggregation operations on a sequence of numbers. The
first operation sums the numbers. The second operation returns the maximum value in the sequence.
The standard query operator methods that perform aggregation operations are listed in the following section.
Methods
C # Q UERY EXP RESSIO N
M ET H O D N A M E DESC RIP T IO N SY N TA X M O RE IN F O RM AT IO N
The term "LINQ to Objects" refers to the use of LINQ queries with any IEnumerable or IEnumerable<T>
collection directly, without the use of an intermediate LINQ provider or API such as LINQ to SQL or LINQ to XML.
You can use LINQ to query any enumerable collections such as List<T>, Array, or Dictionary<TKey,TValue>. The
collection may be user-defined or may be returned by a .NET API.
In a basic sense, LINQ to Objects represents a new approach to collections. In the old way, you had to write
complex foreach loops that specified how to retrieve data from a collection. In the LINQ approach, you write
declarative code that describes what you want to retrieve.
In addition, LINQ queries offer three main advantages over traditional foreach loops:
They are more concise and readable, especially when filtering multiple conditions.
They provide powerful filtering, ordering, and grouping capabilities with a minimum of application code.
They can be ported to other data sources with little or no modification.
In general, the more complex the operation you want to perform on the data, the more benefit you'll realize by
using LINQ instead of traditional iteration techniques.
The purpose of this section is to demonstrate the LINQ approach with some select examples. It's not intended to
be exhaustive.
In This Section
LINQ and Strings (C#)
Explains how LINQ can be used to query and transform strings and collections of strings. Also includes links to
articles that demonstrate these principles.
LINQ and Reflection (C#)
Links to a sample that demonstrates how LINQ uses reflection.
LINQ and File Directories (C#)
Explains how LINQ can be used to interact with file systems. Also includes links to articles that demonstrate
these concepts.
How to query an ArrayList with LINQ (C#)
Demonstrates how to query an ArrayList in C#.
How to add custom methods for LINQ queries (C#)
Explains how to extend the set of methods that you can use for LINQ queries by adding extension methods to
the IEnumerable<T> interface.
Language-Integrated Query (LINQ) (C#)
Provides links to articles that explain LINQ and provide examples of code that perform queries.
LINQ and strings (C#)
9/3/2020 • 2 minutes to read • Edit Online
LINQ can be used to query and transform strings and collections of strings. It can be especially useful with semi-
structured data in text files. LINQ queries can be combined with traditional string functions and regular
expressions. For example, you can use the String.Split or Regex.Split method to create an array of strings that you
can then query or modify by using LINQ. You can use the Regex.IsMatch method in the where clause of a LINQ
query. And you can use LINQ to query or modify the MatchCollection results returned by a regular expression.
You can also use the techniques described in this section to transform semi-structured text data to XML. For more
information, see How to generate XML from CSV files.
The examples in this section fall into two categories:
See also
Language-Integrated Query (LINQ) (C#)
How to generate XML from CSV files
How to count occurrences of a word in a string
(LINQ) (C#)
9/3/2020 • 2 minutes to read • Edit Online
This example shows how to use a LINQ query to count the occurrences of a specified word in a string. Note that to
perform the count, first the Split method is called to create an array of words. There is a performance cost to the
Split method. If the only operation on the string is to count the words, you should consider using the Matches or
IndexOf methods instead. However, if performance is not a critical issue, or you have already split the sentence in
order to perform other types of queries over it, then it makes sense to use LINQ to count the words or phrases as
well.
Example
class CountWords
{
static void Main()
{
string text = @"Historically, the world of data and the world of objects" +
@" have not been well integrated. Programmers work in C# or Visual Basic" +
@" and also in SQL or XQuery. On the one side are concepts such as classes," +
@" objects, fields, inheritance, and .NET Framework APIs. On the other side" +
@" are tables, columns, rows, nodes, and separate languages for dealing with" +
@" them. Data types often require translation between the two worlds; there are" +
@" different standard functions. Because the object world has no notion of query, a" +
@" query can only be represented as a string without compile-time type checking or" +
@" IntelliSense support in the IDE. Transferring data from SQL tables or XML trees to" +
@" objects in memory is often tedious and error-prone.";
This example shows how to find sentences in a text file that contain matches for each of a specified set of words.
Although the array of search terms is hard-coded in this example, it could also be populated dynamically at
runtime. In this example, the query returns the sentences that contain the words "Historically," "data," and
"integrated."
Example
class FindSentences
{
static void Main()
{
string text = @"Historically, the world of data and the world of objects " +
@"have not been well integrated. Programmers work in C# or Visual Basic " +
@"and also in SQL or XQuery. On the one side are concepts such as classes, " +
@"objects, fields, inheritance, and .NET Framework APIs. On the other side " +
@"are tables, columns, rows, nodes, and separate languages for dealing with " +
@"them. Data types often require translation between the two worlds; there are " +
@"different standard functions. Because the object world has no notion of query, a " +
@"query can only be represented as a string without compile-time type checking or " +
@"IntelliSense support in the IDE. Transferring data from SQL tables or XML trees to " +
@"objects in memory is often tedious and error-prone.";
// Define the search terms. This list could also be dynamically populated at runtime.
string[] wordsToMatch = { "Historically", "data", "integrated" };
// Find sentences that contain all the terms in the wordsToMatch array.
// Note that the number of terms to match is not specified at compile time.
var sentenceQuery = from sentence in sentences
let w = sentence.Split(new char[] { '.', '?', '!', ' ', ';', ':', ',' },
StringSplitOptions.RemoveEmptyEntries)
where w.Distinct().Intersect(wordsToMatch).Count() == wordsToMatch.Count()
select sentence;
The query works by first splitting the text into sentences, and then splitting the sentences into an array of strings
that hold each word. For each of these arrays, the Distinct method removes all duplicate words, and then the query
performs an Intersect operation on the word array and the wordsToMatch array. If the count of the intersection is
the same as the count of the wordsToMatch array, all words were found in the words and the original sentence is
returned.
In the call to Split, the punctuation marks are used as separators in order to remove them from the string. If you
did not do this, for example you could have a string "Historically," that would not match "Historically" in the
wordsToMatch array. You may have to use additional separators, depending on the types of punctuation found in
the source text.
See also
LINQ and Strings (C#)
How to query for characters in a string (LINQ) (C#)
9/3/2020 • 2 minutes to read • Edit Online
Because the String class implements the generic IEnumerable<T> interface, any string can be queried as a
sequence of characters. However, this is not a common use of LINQ. For complex pattern matching operations, use
the Regex class.
Example
The following example queries a string to determine the number of numeric digits it contains. Note that the query
is "reused" after it is executed the first time. This is possible because the query itself does not store any actual
results.
class QueryAString
{
static void Main()
{
string aString = "ABCDE99F-J74-12-89A";
See also
LINQ and Strings (C#)
How to combine LINQ queries with regular expressions (C#)
How to combine LINQ queries with regular
expressions (C#)
9/3/2020 • 2 minutes to read • Edit Online
This example shows how to use the Regex class to create a regular expression for more complex matching in text
strings. The LINQ query makes it easy to filter on exactly the files that you want to search with the regular
expression, and to shape the results.
Example
class QueryWithRegEx
{
public static void Main()
{
// Modify this path as necessary so that it accesses your version of Visual Studio.
string startFolder = @"C:\Program Files (x86)\Microsoft Visual Studio 14.0\";
// One of the following paths may be more appropriate on your computer.
//string startFolder = @"C:\Program Files (x86)\Microsoft Visual Studio\2017\";
Note that you can also query the MatchCollection object that is returned by a RegEx search. In this example only
the value of each match is produced in the results. However, it is also possible to use LINQ to perform all kinds of
filtering, sorting, and grouping on that collection. Because MatchCollection is a non-generic IEnumerable
collection, you have to explicitly state the type of the range variable in the query.
See also
LINQ and Strings (C#)
LINQ and File Directories (C#)
How to find the set difference between two lists
(LINQ) (C#)
9/3/2020 • 2 minutes to read • Edit Online
This example shows how to use LINQ to compare two lists of strings and output those lines that are in names1.txt
but not in names2.txt.
To create the data files
1. Copy names1.txt and names2.txt to your solution folder as shown in How to combine and compare string
collections (LINQ) (C#).
Example
class CompareLists
{
static void Main()
{
// Create the IEnumerable data sources.
string[] names1 = System.IO.File.ReadAllLines(@"../../../names1.txt");
string[] names2 = System.IO.File.ReadAllLines(@"../../../names2.txt");
// Create the query. Note that method syntax must be used here.
IEnumerable<string> differenceQuery =
names1.Except(names2);
Some types of query operations in C#, such as Except, Distinct, Union, and Concat, can only be expressed in
method-based syntax.
See also
LINQ and Strings (C#)
How to sort or filter text data by any word or field
(LINQ) (C#)
9/3/2020 • 2 minutes to read • Edit Online
The following example shows how to sort lines of structured text, such as comma-separated values, by any field in
the line. The field may be dynamically specified at runtime. Assume that the fields in scores.csv represent a
student's ID number, followed by a series of four test scores.
To create a file that contains data
1. Copy the scores.csv data from the topic How to join content from dissimilar files (LINQ) (C#) and save it to your
solution folder.
Example
public class SortLines
{
static void Main()
{
// Create an IEnumerable data source
string[] scores = System.IO.File.ReadAllLines(@"../../../scores.csv");
return scoreQuery;
}
}
/* Output (if sortField == 1):
Sorted highest to lowest by field [1]:
116, 99, 86, 90, 94
120, 99, 82, 81, 79
111, 97, 92, 81, 60
114, 97, 89, 85, 82
121, 96, 85, 91, 60
122, 94, 92, 91, 91
117, 93, 92, 80, 87
118, 92, 90, 83, 78
113, 88, 94, 65, 91
112, 75, 84, 91, 39
119, 68, 79, 88, 92
115, 35, 72, 91, 70
*/
This example also demonstrates how to return a query variable from a method.
See also
LINQ and Strings (C#)
How to reorder the fields of a delimited file (LINQ)
(C#)
9/3/2020 • 2 minutes to read • Edit Online
A comma-separated value (CSV) file is a text file that is often used to store spreadsheet data or other tabular data
that is represented by rows and columns. By using the Split method to separate the fields, it is very easy to query
and manipulate CSV files by using LINQ. In fact, the same technique can be used to reorder the parts of any
structured line of text; it is not limited to CSV files.
In the following example, assume that the three columns represent students' "last name," "first name", and "ID." The
fields are in alphabetical order based on the students' last names. The query produces a new sequence in which the
ID column appears first, followed by a second column that combines the student's first name and last name. The
lines are reordered according to the ID field. The results are saved into a new file and the original data is not
modified.
To create the data file
1. Copy the following lines into a plain text file that is named spreadsheet1.csv. Save the file in your project
folder.
Adams,Terry,120
Fakhouri,Fadi,116
Feng,Hanying,117
Garcia,Cesar,114
Garcia,Debra,115
Garcia,Hugo,118
Mortensen,Sven,113
O'Donnell,Claire,112
Omelchenko,Svetlana,111
Tucker,Lance,119
Tucker,Michael,122
Zabokritski,Eugene,121
Example
class CSVFiles
{
static void Main(string[] args)
{
// Create the IEnumerable data source
string[] lines = System.IO.File.ReadAllLines(@"../../../spreadsheet1.csv");
// Execute the query and write out the new file. Note that WriteAllLines
// takes a string[], so ToArray is called on the query.
System.IO.File.WriteAllLines(@"../../../spreadsheet2.csv", query.ToArray());
See also
LINQ and Strings (C#)
LINQ and File Directories (C#)
How to generate XML from CSV files (C#)
How to combine and compare string collections
(LINQ) (C#)
9/3/2020 • 2 minutes to read • Edit Online
This example shows how to merge files that contain lines of text and then sort the results. Specifically, it shows
how to perform a simple concatenation, a union, and an intersection on the two sets of text lines.
To set up the project and the text files
1. Copy these names into a text file that is named names1.txt and save it in your project folder:
Bankov, Peter
Holm, Michael
Garcia, Hugo
Potra, Cristina
Noriega, Fabricio
Aw, Kam Foo
Beebe, Ann
Toyoshima, Tim
Guy, Wey Yuan
Garcia, Debra
2. Copy these names into a text file that is named names2.txt and save it in your project folder. Note that the
two files have some names in common.
Liu, Jinghao
Bankov, Peter
Holm, Michael
Garcia, Hugo
Beebe, Ann
Gilchrist, Beth
Myrcha, Jacek
Giakoumakis, Leo
McLin, Nkenge
El Yassir, Mehdi
Example
class MergeStrings
{
static void Main(string[] args)
{
//Put text files in your solution folder
string[] fileA = System.IO.File.ReadAllLines(@"../../../names1.txt");
string[] fileB = System.IO.File.ReadAllLines(@"../../../names2.txt");
IEnumerable<String> tempQuery1 =
from name in fileA
let n = name.Split(',')
where n[0] == nameMatch
select name;
IEnumerable<string> tempQuery2 =
from name2 in fileB
let n2 = name2.Split(',')
where n2[0] == nameMatch
select name2;
IEnumerable<string> nameMatchQuery =
tempQuery1.Concat(tempQuery2).OrderBy(s => s);
OutputQueryResults(nameMatchQuery, $"Concat based on partial name match \"{nameMatch}\":");
See also
LINQ and Strings (C#)
LINQ and File Directories (C#)
How to populate object collections from multiple
sources (LINQ) (C#)
9/3/2020 • 4 minutes to read • Edit Online
This example shows how to merge data from different sources into a sequence of new types.
NOTE
Don't try to join in-memory data or data in the file system with data that is still in a database. Such cross-domain joins can
yield undefined results because of different ways in which join operations might be defined for database queries and other
types of sources. Additionally, there is a risk that such an operation could cause an out-of-memory exception if the amount
of data in the database is large enough. To join data from a database to in-memory data, first call ToList or ToArray on
the database query, and then perform the join on the returned collection.
Example
The following example shows how to use a named type Student to store merged data from two in-memory
collections of strings that simulate spreadsheet data in .csv format. The first collection of strings represents the
student names and IDs, and the second collection represents the student ID (in the first column) and four exam
scores. The ID is used as the foreign key.
using System;
using System.Collections.Generic;
using System.Linq;
class Student
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int ID { get; set; }
public List<int> ExamScores { get; set; }
}
class PopulateCollection
{
static void Main()
{
// These data files are defined in How to join content from
// dissimilar files (LINQ).
In the select clause, an object initializer is used to instantiate each new Student object by using the data from the
two sources.
If you don't have to store the results of a query, anonymous types can be more convenient than named types.
Named types are required if you pass the query results outside the method in which the query is executed. The
following example executes the same task as the previous example, but uses anonymous types instead of named
types:
// Merge the data sources by using an anonymous type.
// Note the dynamic creation of a list of ints for the
// ExamScores member. We skip 1 because the first string
// in the array is the student ID, not an exam score.
var queryNamesScores2 =
from nameLine in names
let splitName = nameLine.Split(',')
from scoreLine in scores
let splitScoreLine = scoreLine.Split(',')
where Convert.ToInt32(splitName[2]) == Convert.ToInt32(splitScoreLine[0])
select new
{
First = splitName[0],
Last = splitName[1],
ExamScores = (from scoreAsText in splitScoreLine.Skip(1)
select Convert.ToInt32(scoreAsText))
.ToList()
};
See also
LINQ and Strings (C#)
Object and Collection Initializers
Anonymous Types
How to split a file into many files by using groups
(LINQ) (C#)
9/3/2020 • 2 minutes to read • Edit Online
This example shows one way to merge the contents of two files and then create a set of new files that organize the
data in a new way.
To create the data files
1. Copy these names into a text file that is named names1.txt and save it in your project folder:
Bankov, Peter
Holm, Michael
Garcia, Hugo
Potra, Cristina
Noriega, Fabricio
Aw, Kam Foo
Beebe, Ann
Toyoshima, Tim
Guy, Wey Yuan
Garcia, Debra
2. Copy these names into a text file that is named names2.txt and save it in your project folder: Note that the
two files have some names in common.
Liu, Jinghao
Bankov, Peter
Holm, Michael
Garcia, Hugo
Beebe, Ann
Gilchrist, Beth
Myrcha, Jacek
Giakoumakis, Leo
McLin, Nkenge
El Yassir, Mehdi
Example
class SplitWithGroups
{
static void Main()
{
string[] fileA = System.IO.File.ReadAllLines(@"../../../names1.txt");
string[] fileB = System.IO.File.ReadAllLines(@"../../../names2.txt");
// Output to display.
Console.WriteLine(g.Key);
// Write file.
using (System.IO.StreamWriter sw = new System.IO.StreamWriter(fileName))
{
foreach (var item in g)
{
sw.WriteLine(item);
// Output to console for example purposes.
Console.WriteLine(" {0}", item);
}
}
}
// Keep console window open in debug mode.
Console.WriteLine("Files have been written. Press any key to exit");
Console.ReadKey();
}
}
/* Output:
A
Aw, Kam Foo
B
Bankov, Peter
Beebe, Ann
E
El Yassir, Mehdi
G
Garcia, Hugo
Guy, Wey Yuan
Garcia, Debra
Gilchrist, Beth
Giakoumakis, Leo
H
Holm, Michael
L
Liu, Jinghao
M
Myrcha, Jacek
McLin, Nkenge
N
Noriega, Fabricio
P
Potra, Cristina
T
Toyoshima, Tim
*/
The program writes a separate file for each group in the same folder as the data files.
See also
LINQ and Strings (C#)
LINQ and File Directories (C#)
How to join content from dissimilar files (LINQ) (C#)
9/3/2020 • 2 minutes to read • Edit Online
This example shows how to join data from two comma-delimited files that share a common value that is used as a
matching key. This technique can be useful if you have to combine data from two spreadsheets, or from a
spreadsheet and from a file that has another format, into a new file. You can modify the example to work with any
kind of structured text.
2. Copy the following lines into a file that is named names.csv and save it to your project folder. The file
represents a spreadsheet that contains the student's last name, first name, and student ID.
Omelchenko,Svetlana,111
O'Donnell,Claire,112
Mortensen,Sven,113
Garcia,Cesar,114
Garcia,Debra,115
Fakhouri,Fadi,116
Feng,Hanying,117
Garcia,Hugo,118
Tucker,Lance,119
Adams,Terry,120
Zabokritski,Eugene,121
Tucker,Michael,122
Example
using System;
using System.Collections.Generic;
using System.Linq;
class JoinStrings
{
static void Main()
{
// Join content from dissimilar files that contain
// related information. File names.csv contains the student
// name plus an ID number. File scores.csv contains the ID
// and a set of four test scores. The following query joins
// the scores to the student names by using ID as a
// matching key.
See also
LINQ and Strings (C#)
LINQ and File Directories (C#)
How to compute column values in a CSV text file
(LINQ) (C#)
9/3/2020 • 3 minutes to read • Edit Online
This example shows how to perform aggregate computations such as Sum, Average, Min, and Max on the columns
of a .csv file. The example principles that are shown here can be applied to other types of structured text.
Example
class SumColumns
{
static void Main(string[] args)
{
string[] lines = System.IO.File.ReadAllLines(@"../../../scores.csv");
// Spreadsheet format:
// Student ID Exam#1 Exam#2 Exam#3 Exam#4
// 111, 97, 92, 81, 60
The query works by using the Split method to convert each line of text into an array. Each array element represents
a column. Finally, the text in each column is converted to its numeric representation. If your file is a tab-separated
file, just update the argument in the Split method to \t .
See also
LINQ and Strings (C#)
LINQ and File Directories (C#)
How to query an assembly's metadata with Reflection
(LINQ) (C#)
9/3/2020 • 2 minutes to read • Edit Online
The .NET reflection APIs can be used to examine the metadata in a .NET assembly and create collections of types,
type members, parameters, and so on that are in that assembly. Because these collections support the generic
IEnumerable<T> interface, they can be queried by using LINQ.
The following example shows how LINQ can be used with reflection to retrieve specific metadata about methods
that match a specified search criterion. In this case, the query will find the names of all the methods in the assembly
that return enumerable types such as arrays.
Example
using System;
using System.Linq;
using System.Reflection;
class ReflectionHowTO
{
static void Main()
{
Assembly assembly = Assembly.Load("System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=
b77a5c561934e089");
var pubTypesQuery = from type in assembly.GetTypes()
where type.IsPublic
from method in type.GetMethods()
where method.ReturnType.IsArray == true
|| ( method.ReturnType.GetInterface(
typeof(System.Collections.Generic.IEnumerable<>).FullName ) != null
&& method.ReturnType.FullName != "System.String" )
group method.ToString() by type.ToString();
The example uses the Assembly.GetTypes method to return an array of types in the specified assembly. The where
filter is applied so that only public types are returned. For each public type, a subquery is generated by using the
MethodInfo array that is returned from the Type.GetMethods call. These results are filtered to return only those
methods whose return type is an array or else a type that implements IEnumerable<T>. Finally, these results are
grouped by using the type name as a key.
See also
LINQ to Objects (C#)
How to query an assembly's metadata with
Reflection (LINQ) (C#)
9/3/2020 • 2 minutes to read • Edit Online
The .NET reflection APIs can be used to examine the metadata in a .NET assembly and create collections of types,
type members, parameters, and so on that are in that assembly. Because these collections support the generic
IEnumerable<T> interface, they can be queried by using LINQ.
The following example shows how LINQ can be used with reflection to retrieve specific metadata about methods
that match a specified search criterion. In this case, the query will find the names of all the methods in the
assembly that return enumerable types such as arrays.
Example
using System;
using System.Linq;
using System.Reflection;
class ReflectionHowTO
{
static void Main()
{
Assembly assembly = Assembly.Load("System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=
b77a5c561934e089");
var pubTypesQuery = from type in assembly.GetTypes()
where type.IsPublic
from method in type.GetMethods()
where method.ReturnType.IsArray == true
|| ( method.ReturnType.GetInterface(
typeof(System.Collections.Generic.IEnumerable<>).FullName ) != null
&& method.ReturnType.FullName != "System.String" )
group method.ToString() by type.ToString();
The example uses the Assembly.GetTypes method to return an array of types in the specified assembly. The where
filter is applied so that only public types are returned. For each public type, a subquery is generated by using the
MethodInfo array that is returned from the Type.GetMethods call. These results are filtered to return only those
methods whose return type is an array or else a type that implements IEnumerable<T>. Finally, these results are
grouped by using the type name as a key.
See also
LINQ to Objects (C#)
LINQ and file directories (C#)
9/3/2020 • 2 minutes to read • Edit Online
Many file system operations are essentially queries and are therefore well suited to the LINQ approach.
The queries in this section are non-destructive. They are not used to change the contents of the original files or
folders. This follows the rule that queries should not cause any side-effects. In general, any code (including
queries that perform create / update / delete operators) that modifies source data should be kept separate from
the code that just queries the data.
This section contains the following topics:
How to query for files with a specified attribute or name (C#)
Shows how to search for files by examining one or more properties of its FileInfo object.
How to group files by extension (LINQ) (C#)
Shows how to return groups of FileInfo object based on their file name extension.
How to query for the total number of bytes in a set of folders (LINQ) (C#)
Shows how to return the total number of bytes in all the files in a specified directory tree.
How to compare the contents of two folders (LINQ) (C#)s
Shows how to return all the files that are present in two specified folders, and also all the files that are present in
one folder but not the other.
How to query for the largest file or files in a directory tree (LINQ) (C#)
Shows how to return the largest or smallest file, or a specified number of files, in a directory tree.
How to query for duplicate files in a directory tree (LINQ) (C#)
Shows how to group for all file names that occur in more than one location in a specified directory tree. Also
shows how to perform more complex comparisons based on a custom comparer.
How to query the contents of files in a folder (LINQ) (C#)
Shows how to iterate through folders in a tree, open each file, and query the file's contents.
Comments
There is some complexity involved in creating a data source that accurately represents the contents of the file
system and handles exceptions gracefully. The examples in this section create a snapshot collection of FileInfo
objects that represents all the files under a specified root folder and all its subfolders. The actual state of each
FileInfo may change in the time between when you begin and end executing a query. For example, you can
create a list of FileInfo objects to use as a data source. If you try to access the Length property in a query, the
FileInfo object will try to access the file system to update the value of Length . If the file no longer exists, you will
get a FileNotFoundException in your query, even though you are not querying the file system directly. Some
queries in this section use a separate method that consumes these particular exceptions in certain cases.
Another option is to keep your data source updated dynamically by using the FileSystemWatcher.
See also
LINQ to Objects (C#)
How to query for files with a specified attribute or
name (C#)
9/3/2020 • 2 minutes to read • Edit Online
This example shows how to find all files that have a specified file name extension (for example ".txt") in a specified
directory tree. It also shows how to return either the newest or oldest file in the tree based on the creation time.
Example
class FindFileByExtension
{
// This query will produce the full path for all .txt files
// under the specified folder including subfolders.
// It orders the list according to the file name.
static void Main()
{
string startFolder = @"c:\program files\Microsoft Visual Studio 9.0\";
See also
LINQ to Objects (C#)
LINQ and File Directories (C#)
How to group files by extension (LINQ) (C#)
9/3/2020 • 2 minutes to read • Edit Online
This example shows how LINQ can be used to perform advanced grouping and sorting operations on lists of files
or folders. It also shows how to page output in the console window by using the Skip and Take methods.
Example
The following query shows how to group the contents of a specified directory tree by the file name extension.
class GroupByExtension
{
// This query will sort all the files under the specified folder
// and subfolder into groups keyed by the file extension.
private static void Main()
{
// Take a snapshot of the file system.
string startFolder = @"c:\program files\Microsoft Visual Studio 9.0\Common7";
// This method specifically handles group queries of FileInfo objects with string keys.
// It can be modified to work for any long listings of data. Note that explicit typing
// must be used in method signatures. The groupbyExtList parameter is a query that produces
// groups of FileInfo objects with string keys.
private static void PageOutput(int rootLength,
IEnumerable<System.Linq.IGrouping<string, System.IO.FileInfo>>
groupByExtList)
{
// Flag to break out of paging loop.
bool goAgain = true;
// "3" = 1 line for extension + 1 for "Press any key" + 1 for input cursor.
int numLines = Console.WindowHeight - 3;
// Output only as many lines of the current group as will fit in the window.
do
{
Console.Clear();
Console.WriteLine(filegroup.Key == String.Empty ? "[none]" : filegroup.Key);
if (goAgain == false)
break;
}
}
}
The output from this program can be long, depending on the details of the local file system and what the
startFolder is set to. To enable viewing of all results, this example shows how to page through results. The same
techniques can be applied to Windows and Web applications. Notice that because the code pages the items in a
group, a nested foreach loop is required. There is also some additional logic to compute the current position in
the list, and to enable the user to stop paging and exit the program. In this particular case, the paging query is run
against the cached results from the original query. In other contexts, such as LINQ to SQL, such caching is not
required.
See also
LINQ to Objects (C#)
LINQ and File Directories (C#)
How to query for the total number of bytes in a set
of folders (LINQ) (C#)
9/3/2020 • 2 minutes to read • Edit Online
This example shows how to retrieve the total number of bytes used by all the files in a specified folder and all its
subfolders.
Example
The Sum method adds the values of all the items selected in the select clause. You can easily modify this query to
retrieve the biggest or smallest file in the specified directory tree by calling the Min or Max method instead of Sum.
class QuerySize
{
public static void Main()
{
string startFolder = @"c:\program files\Microsoft Visual Studio 9.0\VC#";
// Return the total number of bytes in all the files under the specified folder.
long totalBytes = fileLengths.Sum();
If you only have to count the number of bytes in a specified directory tree, you can do this more efficiently without
creating a LINQ query, which incurs the overhead of creating the list collection as a data source. The usefulness of
the LINQ approach increases as the query becomes more complex, or when you have to run multiple queries
against the same data source.
The query calls out to a separate method to obtain the file length. It does this in order to consume the possible
exception that will be raised if the file was deleted on another thread after the FileInfo object was created in the call
to GetFiles . Even though the FileInfo object has already been created, the exception can occur because a FileInfo
object will try to refresh its Length property with the most current length the first time the property is accessed. By
putting this operation in a try-catch block outside the query, the code follows the rule of avoiding operations in
queries that can cause side-effects. In general, great care must be taken when you consume exceptions to make
sure that an application is not left in an unknown state.
See also
LINQ to Objects (C#)
LINQ and File Directories (C#)
How to compare the contents of two folders (LINQ)
(C#)
9/3/2020 • 2 minutes to read • Edit Online
NOTE
The techniques shown here can be adapted to compare sequences of objects of any type.
The FileComparer class shown here demonstrates how to use a custom comparer class together with the Standard
Query Operators. The class is not intended for use in real-world scenarios. It just uses the name and length in bytes
of each file to determine whether the contents of each folder are identical or not. In a real-world scenario, you
should modify this comparer to perform a more rigorous equality check.
Example
namespace QueryCompareTwoDirs
{
class CompareDirs
{
if (areIdentical == true)
{
Console.WriteLine("the two folders are the same");
Console.WriteLine("the two folders are the same");
}
else
{
Console.WriteLine("The two folders are not the same");
}
if (queryCommonFiles.Any())
{
Console.WriteLine("The following files are in both folders:");
foreach (var v in queryCommonFiles)
{
Console.WriteLine(v.FullName); //shows which items end up in result list
}
}
else
{
Console.WriteLine("There are no common files in the two folders.");
}
See also
LINQ to Objects (C#)
LINQ and File Directories (C#)
How to query for the largest file or files in a directory
tree (LINQ) (C#)
9/3/2020 • 3 minutes to read • Edit Online
Example
The following example contains five separate queries that show how to query and group files, depending on their
file size in bytes. You can easily modify these examples to base the query on some other property of the FileInfo
object.
class QueryBySize
{
static void Main(string[] args)
{
QueryFilesBySize();
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
Console.WriteLine("The largest file under {0} is {1} with a length of {2} bytes",
startFolder, longestFile.FullName, longestFile.Length);
Console.WriteLine("The smallest file under {0} is {1} with a length of {2} bytes",
startFolder, smallestFile.FullName, smallestFile.Length);
To return one or more complete FileInfo objects, the query first must examine each one in the data source, and
then sort them by the value of their Length property. Then it can return the single one or the sequence with the
greatest lengths. Use First to return the first element in a list. Use Take to return the first n number of elements.
Specify a descending sort order to put the smallest elements at the start of the list.
The query calls out to a separate method to obtain the file size in bytes in order to consume the possible exception
that will be raised in the case where a file was deleted on another thread in the time period since the FileInfo object
was created in the call to GetFiles . Even through the FileInfo object has already been created, the exception can
occur because a FileInfo object will try to refresh its Length property by using the most current size in bytes the
first time the property is accessed. By putting this operation in a try-catch block outside the query, we follow the
rule of avoiding operations in queries that can cause side-effects. In general, great care must be taken when
consuming exceptions, to make sure that an application is not left in an unknown state.
See also
LINQ to Objects (C#)
LINQ and File Directories (C#)
How to query for duplicate files in a directory tree
(LINQ) (C#)
9/3/2020 • 3 minutes to read • Edit Online
Sometimes files that have the same name may be located in more than one folder. For example, under the Visual
Studio installation folder, several folders have a readme.htm file. This example shows how to query for such
duplicate file names under a specified root folder. The second example shows how to query for files whose size and
LastWrite times also match.
Example
class QueryDuplicateFileNames
{
static void Main(string[] args)
{
// Uncomment QueryDuplicates2 to run that query.
QueryDuplicates();
// QueryDuplicates2();
int i = queryDupFiles.Count();
PageOutput<PortableKey, string>(queryDupFiles);
}
// "3" = 1 line for extension + 1 for "Press any key" + 1 for input cursor.
int numLines = Console.WindowHeight - 3;
// Output only as many lines of the current group as will fit in the window.
do
{
Console.Clear();
Console.WriteLine("Filename = {0}", filegroup.Key.ToString() == String.Empty ? "[none]" :
filegroup.Key.ToString());
if (goAgain == false)
break;
}
}
}
The first query uses a simple key to determine a match; this finds files that have the same name but whose
contents might be different. The second query uses a compound key to match against three properties of the
FileInfo object. This query is much more likely to find files that have the same name and similar or identical
content.
See also
LINQ to Objects (C#)
LINQ and File Directories (C#)
How to query the contents of text files in a folder
(LINQ) (C#)
9/3/2020 • 2 minutes to read • Edit Online
This example shows how to query over all the files in a specified directory tree, open each file, and inspect its
contents. This type of technique could be used to create indexes or reverse indexes of the contents of a directory
tree. A simple string search is performed in this example. However, more complex types of pattern matching can be
performed with a regular expression. For more information, see How to combine LINQ queries with regular
expressions (C#).
Example
class QueryContents
{
public static void Main()
{
// Modify this path as necessary.
string startFolder = @"c:\program files\Microsoft Visual Studio 9.0\";
See also
LINQ and File Directories (C#)
LINQ to Objects (C#)
How to query an ArrayList with LINQ (C#)
9/3/2020 • 2 minutes to read • Edit Online
When using LINQ to query non-generic IEnumerable collections such as ArrayList, you must explicitly declare the
type of the range variable to reflect the specific type of the objects in the collection. For example, if you have an
ArrayList of Student objects, your from clause should look like this:
By specifying the type of the range variable, you are casting each item in the ArrayList to a Student .
The use of an explicitly typed range variable in a query expression is equivalent to calling the Cast method. Cast
throws an exception if the specified cast cannot be performed. Cast and OfType are the two Standard Query
Operator methods that operate on non-generic IEnumerable types. For more information, see Type Relationships
in LINQ Query Operations.
Example
The following example shows a simple query over an ArrayList. Note that this example uses object initializers
when the code calls the Add method, but this is not a requirement.
using System;
using System.Collections;
using System.Linq;
namespace NonGenericLINQ
{
public class Student
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int[] Scores { get; set; }
}
class Program
{
static void Main(string[] args)
{
ArrayList arrList = new ArrayList();
arrList.Add(
new Student
{
FirstName = "Svetlana", LastName = "Omelchenko", Scores = new int[] { 98, 92, 81, 60
}
});
arrList.Add(
new Student
{
FirstName = "Claire", LastName = "O’Donnell", Scores = new int[] { 75, 84, 91, 39 }
});
arrList.Add(
new Student
{
FirstName = "Sven", LastName = "Mortensen", Scores = new int[] { 88, 94, 65, 91 }
});
arrList.Add(
new Student
{
FirstName = "Cesar", LastName = "Garcia", Scores = new int[] { 97, 89, 85, 82 }
});
See also
LINQ to Objects (C#)
How to add custom methods for LINQ queries (C#)
9/3/2020 • 5 minutes to read • Edit Online
You extend the set of methods that you use for LINQ queries by adding extension methods to the IEnumerable<T>
interface. For example, in addition to the standard average or maximum operations, you create a custom aggregate
method to compute a single value from a sequence of values. You also create a method that works as a custom
filter or a specific data transform for a sequence of values and returns a new sequence. Examples of such methods
are Distinct, Skip, and Reverse.
When you extend the IEnumerable<T> interface, you can apply your custom methods to any enumerable
collection. For more information, see Extension Methods.
if (sortedList.Count % 2 == 0)
{
// Even number of items.
return (sortedList[itemIndex] + sortedList[itemIndex - 1]) / 2;
}
else
{
// Odd number of items.
return sortedList[itemIndex];
}
}
}
You call this extension method for any enumerable collection in the same way you call other aggregate methods
from the IEnumerable<T> interface.
The following code example shows how to use the Median method for an array of type double .
double[] numbers = { 1.9, 2, 8, 4, 5.7, 6, 7.2, 0 };
//int overload
public static double Median(this IEnumerable<int> source) =>
(from num in source select (double)num).Median();
You can now call the Median overloads for both integer and double types, as shown in the following code:
int[] numbers2 = { 1, 2, 3, 4, 5 };
// Generic overload.
public static double Median<T>(this IEnumerable<T> numbers,
Func<T, double> selector) =>
(from num in numbers select selector(num)).Median();
You can now call the Median method for a sequence of objects of any type. If the type doesn't have its own method
overload, you have to pass a delegate parameter. In C#, you can use a lambda expression for this purpose. Also, in
Visual Basic only, if you use the Aggregate or Group By clause instead of the method call, you can pass any value
or expression that is in the scope this clause.
The following example code shows how to call the Median method for an array of integers and an array of strings.
For strings, the median for the lengths of strings in the array is calculated. The example shows how to pass the
Func<T,TResult> delegate parameter to the Median method for each case.
int[] numbers3 = { 1, 2, 3, 4, 5 };
/*
You can use the num=>num lambda expression as a parameter for the Median method
so that the compiler will implicitly convert its value to double.
If there is no implicit conversion, the compiler will display an error message.
*/
var query3 = numbers3.Median(num => num);
// With the generic overload, you can also use numeric properties of objects.
/*
This code produces the following output:
Integer: Median = 3
String: Median = 4
*/
You can call this extension method for any enumerable collection just as you would call other methods from the
IEnumerable<T> interface, as shown in the following code:
string[] strings = { "a", "b", "c", "d", "e" };
a
c
e
*/
See also
IEnumerable<T>
Extension Methods
LINQ to XML Overview (C#)
9/3/2020 • 4 minutes to read • Edit Online
LINQ to XML provides an in-memory XML programming interface that leverages the .NET Language-Integrated
Query (LINQ) Framework. LINQ to XML uses .NET capabilities and is comparable to an updated, redesigned
Document Object Model (DOM) XML programming interface.
XML has been widely adopted as a way to format data in many contexts. For example, you can find XML on the
Web, in configuration files, in Microsoft Office Word files, and in databases.
LINQ to XML is an up-to-date, redesigned approach to programming with XML. It provides the in-memory
document modification capabilities of the Document Object Model (DOM), and supports LINQ query
expressions. Although these query expressions are syntactically different from XPath, they provide similar
functionality.
As another example, you might want a list, sorted by part number, of the items with a value greater than $100.
To obtain this information, you could run the following query:
// Load the XML file from our project directory containing the purchase orders
var filename = "PurchaseOrder.xml";
var currentDirectory = Directory.GetCurrentDirectory();
var purchaseOrderFilepath = Path.Combine(currentDirectory, filename);
In addition to these LINQ capabilities, LINQ to XML provides an improved XML programming interface. Using
LINQ to XML, you can:
Load XML from files or streams.
Serialize XML to files or streams.
Create XML from scratch by using functional construction.
Query XML using XPath-like axes.
Manipulate the in-memory XML tree by using methods such as Add, Remove, ReplaceWith, and SetValue.
Validate XML trees using XSD.
Use a combination of these features to transform XML trees from one shape into another.
See also
Reference (LINQ to XML)
LINQ to XML vs. DOM (C#)
LINQ to XML vs. Other XML Technologies
System.Xml.Linq
LINQ to XML vs. DOM (C#)
9/3/2020 • 5 minutes to read • Edit Online
This section describes some key differences between LINQ to XML and the current predominant XML
programming API, the W3C Document Object Model (DOM).
This style of coding does not visually provide much information about the structure of the XML tree. LINQ to XML
supports this approach to constructing an XML tree, but also supports an alternative approach, functional
construction. Functional construction uses the XElement and XAttribute constructors to build an XML tree.
Here is how you would construct the same XML tree by using LINQ to XML functional construction:
XElement contacts =
new XElement("Contacts",
new XElement("Contact",
new XElement("Name", "Patrick Hines"),
new XElement("Phone", "206-555-0144",
new XAttribute("Type", "Home")),
new XElement("phone", "425-555-0145",
new XAttribute("Type", "Work")),
new XElement("Address",
new XElement("Street1", "123 Main St"),
new XElement("City", "Mercer Island"),
new XElement("State", "WA"),
new XElement("Postal", "68042")
)
)
);
Notice that indenting the code to construct the XML tree shows the structure of the underlying XML.
For more information, see Creating XML Trees (C#).
If you want to use an element across multiple documents, you must import the nodes across documents. LINQ to
XML avoids this layer of complexity.
When using LINQ to XML, you use the XDocument class only if you want to add a comment or processing
instruction at the root level of the document.
See also
Getting Started (LINQ to XML)
LINQ to XML vs. Other XML Technologies
9/3/2020 • 3 minutes to read • Edit Online
This topic compares LINQ to XML to the following XML technologies: XmlReader, XSLT, MSXML, and XmlLite. This
information can help you decide which technology to use.
For a comparison of LINQ to XML to the Document Object Model (DOM), see LINQ to XML vs. DOM (C#).
See also
Getting Started (LINQ to XML)
Functional vs. Procedural Programming (LINQ to
XML) (C#)
9/3/2020 • 2 minutes to read • Edit Online
See also
LINQ to XML Programming Overview (C#)
LINQ to XML Classes Overview (C#)
9/3/2020 • 2 minutes to read • Edit Online
This topic provides a list of the LINQ to XML classes in the System.Xml.Linq namespace, and a short description of
each.
See also
LINQ to XML Programming Overview (C#)
XElement Class Overview (C#)
9/3/2020 • 2 minutes to read • Edit Online
The XElement class is one of the fundamental classes in LINQ to XML. It represents an XML element. You can use
this class to create elements; change the content of the element; add, change, or delete child elements; add
attributes to an element; or serialize the contents of an element in text form. You can also interoperate with other
classes in System.Xml, such as XmlReader, XmlWriter, and XslCompiledTransform.
This topic describes the functionality provided by the XElement class.
XElement contacts =
new XElement("Contacts",
new XElement("Contact",
new XElement("Name", "Patrick Hines"),
new XElement("Phone", "206-555-0144"),
new XElement("Address",
new XElement("Street1", "123 Main St"),
new XElement("City", "Mercer Island"),
new XElement("State", "WA"),
new XElement("Postal", "68042")
)
)
);
Another very common technique for creating an XML tree involves using the results of a LINQ query to populate
an XML tree, as shown in the following example:
XElement srcTree = new XElement("Root",
new XElement("Element", 1),
new XElement("Element", 2),
new XElement("Element", 3),
new XElement("Element", 4),
new XElement("Element", 5)
);
XElement xmlTree = new XElement("Root",
new XElement("Child", 1),
new XElement("Child", 2),
from el in srcTree.Elements()
where (int)el > 2
select el
);
Console.WriteLine(xmlTree);
<Root>
<Child>1</Child>
<Child>2</Child>
<Element>3</Element>
<Element>4</Element>
<Element>5</Element>
</Root>
See also
LINQ to XML Programming Overview (C#)
XAttribute Class Overview (C#)
9/3/2020 • 2 minutes to read • Edit Online
Attributes are name/value pairs that are associated with an element. The XAttribute class represents XML attributes.
Overview
Working with attributes in LINQ to XML is similar to working with elements. Their constructors are similar. The
methods that you use to retrieve collections of them are similar. A LINQ query expression for a collection of
attributes looks very similar to a LINQ query expression for a collection of elements.
The order in which attributes were added to an element is preserved. That is, when you iterate through the
attributes, you see them in the same order that they were added.
XAttribute(XName name, object content) Creates an XAttribute object. The name argument specifies
the name of the attribute; content specifies the content of
the attribute.
<Phone Type="Home">555-555-5555</Phone>
<Customers>
<Customer>
<Name>John Doe</Name>
<PhoneNumbers>
<Phone type="home">555-555-5555</Phone>
<Phone type="work">666-666-6666</Phone>
</PhoneNumbers>
</Customer>
</Customers>
See also
LINQ to XML Programming Overview (C#)
XDocument Class Overview (C#)
9/3/2020 • 2 minutes to read • Edit Online
Components of XDocument
An XDocument can contain the following elements:
One XDeclaration object. XDeclaration enables you to specify the pertinent parts of an XML declaration: the
XML version, the encoding of the document, and whether the XML document is stand-alone.
One XElement object. This is the root node of the XML document.
Any number of XProcessingInstruction objects. A processing instruction communicates information to an
application that processes the XML.
Any number of XComment objects. The comments will be siblings to the root element. The XComment
object cannot be the first argument in the list, because it is not valid for an XML document to start with a
comment.
One XDocumentType for the DTD.
When you serialize an XDocument, even if XDocument.Declaration is null , the output will have an XML declaration
if the writer has Writer.Settings.OmitXmlDeclaration set to false (the default).
By default, LINQ to XML sets the version to "1.0", and sets the encoding to "utf-8".
Using XDocument
To construct an XDocument, use functional construction, just like you do to construct XElement objects.
The following code creates an XDocument object and its associated contained objects.
XDocument d = new XDocument(
new XComment("This is a comment."),
new XProcessingInstruction("xml-stylesheet",
"href='mystyle.css' title='Compact' type='text/css'"),
new XElement("Pubs",
new XElement("Book",
new XElement("Title", "Artifacts of Roman Civilization"),
new XElement("Author", "Moreno, Jordao")
),
new XElement("Book",
new XElement("Title", "Midieval Tools and Implements"),
new XElement("Author", "Gazit, Inbar")
)
),
new XComment("This is another comment.")
);
d.Declaration = new XDeclaration("1.0", "utf-8", "true");
Console.WriteLine(d);
d.Save("test.xml");
When you examine the file test.xml, you get the following output:
See also
LINQ to XML Programming Overview (C#)
How to build LINQ to XML examples (C#)
9/3/2020 • 2 minutes to read • Edit Online
The various snippets and examples in this documentation use classes and types from a variety of namespaces.
When compiling C# code, you need to supply appropriate using directives.
Example
The following code contains the using directives that the C# examples require to build and run. Not all using
directives are required for every example.
using System;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;
using System.Xml.XPath;
using System.Xml.Xsl;
using System.IO;
using System.Threading;
using System.Reflection;
using System.IO.Packaging;
See also
LINQ to XML Programming Overview (C#)
Functional Construction (LINQ to XML) (C#)
9/3/2020 • 2 minutes to read • Edit Online
LINQ to XML provides a powerful way to create XML elements called functional construction. Functional
construction is the ability to create an XML tree in a single statement.
There are several key features of the LINQ to XML programming interface that enable functional construction:
The XElement constructor takes various types of arguments for content. For example, you can pass another
XElement object, which becomes a child element. You can pass an XAttribute object, which becomes an
attribute of the element. Or you can pass any other type of object, which is converted to a string and
becomes the text content of the element.
The XElement constructor takes a params array of type Object, so that you can pass any number of objects
to the constructor. This enables you to create an element that has complex content.
If an object implements IEnumerable<T>, the collection in the object is enumerated, and all items in the
collection are added. If the collection contains XElement or XAttribute objects, each item in the collection is
added separately. This is important because it lets you pass the results of a LINQ query to the constructor.
These features enable you to write code to create an XML tree. The following is an example:
XElement contacts =
new XElement("Contacts",
new XElement("Contact",
new XElement("Name", "Patrick Hines"),
new XElement("Phone", "206-555-0144"),
new XElement("Address",
new XElement("Street1", "123 Main St"),
new XElement("City", "Mercer Island"),
new XElement("State", "WA"),
new XElement("Postal", "68042")
)
)
);
These features also enable you to write code that uses the results of LINQ queries when you create an XML tree, as
follows:
Constructing elements
The signatures of the XElement and XAttribute constructors let you pass the contents of the element or attribute as
arguments to the constructor. Because one of the constructors takes a variable number of arguments, you can pass
any number of child elements. Of course, each of those child elements can contain their own child elements. For
any element, you can add any number of attributes.
When adding XNode (including XElement) or XAttribute objects, if the new content has no parent, the objects are
simply attached to the XML tree. If the new content already is parented, and is part of another XML tree, the new
content is cloned, and the newly cloned content is attached to the XML tree. The last example in this topic
demonstrates this.
To create a contacts XElement, you could use the following code:
XElement contacts =
new XElement("Contacts",
new XElement("Contact",
new XElement("Name", "Patrick Hines"),
new XElement("Phone", "206-555-0144"),
new XElement("Address",
new XElement("Street1", "123 Main St"),
new XElement("City", "Mercer Island"),
new XElement("State", "WA"),
new XElement("Postal", "68042")
)
)
);
If indented properly, the code to construct XElement objects closely resembles the structure of the underlying XML.
XElement constructors
The XElement class uses the following constructors for functional construction. Note that there are some other
constructors for XElement, but because they are not used for functional construction they are not listed here.
XElement(XName name, object content) Creates an XElement. The name parameter specifies the name
of the element; content specifies the content of the element.
XElement(XName name) Creates an XElement with its XName initialized to the specified
name.
C O N ST RUC TO R DESC RIP T IO N
XElement(XName name, params object[] content) Creates an XElement with its XName initialized to the specified
name. The attributes and/or child elements are created from
the contents of the parameter list.
The content parameter is extremely flexible. It supports any type of object that is a valid child of an XElement. The
following rules apply to different types of objects passed in this parameter:
A string is added as text content.
An XElement is added as a child element.
An XAttribute is added as an attribute.
An XProcessingInstruction, XComment, or XText is added as child content.
An IEnumerable is enumerated, and these rules are applied recursively to the results.
For any other type, its ToString method is called and the result is added as text content.
Creating an XElement with content
You can create an XElement that contains simple content with a single method call. To do this, specify the content as
the second parameter, as follows:
<Customer>Adventure Works</Customer>
You can pass any type of object as the content. For example, the following code creates an element that contains a
floating point number as content:
<Cost>324.5</Cost>
The floating point number is boxed and passed in to the constructor. The boxed number is converted to a string
and used as the content of the element.
Creating an XElement with a child element
If you pass an instance of the XElement class for the content argument, the constructor creates an element with a
child element:
<ShippingUnit>
<Cost>324.5</Cost>
</ShippingUnit>
<Address>
<Street1>123 Main St</Street1>
<City>Mercer Island</City>
<State>WA</State>
<Postal>68042</Postal>
</Address>
By extending the above example, you can create an entire XML tree, as follows:
XElement contacts =
new XElement("Contacts",
new XElement("Contact",
new XElement("Name", "Patrick Hines"),
new XElement("Phone", "206-555-0144"),
new XElement("Address",
new XElement("Street1", "123 Main St"),
new XElement("City", "Mercer Island"),
new XElement("State", "WA"),
new XElement("Postal", "68042")
)
)
);
Console.WriteLine(contacts);
<Contacts>
<Contact>
<Name>Patrick Hines</Name>
<Phone>206-555-0144</Phone>
<Address>
<Street1>123 Main St</Street1>
<City>Mercer Island</City>
<State>WA</State>
<Postal>68042</Postal>
</Address>
</Contact>
</Contacts>
Creating an XElement with an XAttribute
If you pass an instance of the XAttribute class for the content argument, the constructor creates an element with an
attribute:
<Phone Type="Home">555-555-5555</Phone>
<Customer />
See also
Creating XML Trees (C#)
How to parse a string (C#)
9/3/2020 • 2 minutes to read • Edit Online
This topic shows how to parse a string to create an XML tree in C#.
Example
The following C# code shows how to parse an XML string:
The root Contacts node has two Contact nodes. To access some specific data in your parsed XML, use the
XElement.Elements() method, which in this case returns the child elements of the root Contacts node. The
following example prints the first Contact node to the console:
See also
How to find an element with a specific attribute (C#)
How to load XML from a file (C#)
9/3/2020 • 2 minutes to read • Edit Online
This topic shows how to load XML from a URI by using the XElement.Load method.
Example
The following example shows how to load an XML document from a file. The following example loads books.xml
and outputs the XML tree to the console.
This example uses the following XML document: Sample XML File: Books (LINQ to XML).
<Catalog>
<Book id="bk101">
<Author>Garghentini, Davide</Author>
<Title>XML Developer's Guide</Title>
<Genre>Computer</Genre>
<Price>44.95</Price>
<PublishDate>2000-10-01</PublishDate>
<Description>An in-depth look at creating applications
with XML.</Description>
</Book>
<Book id="bk102">
<Author>Garcia, Debra</Author>
<Title>Midnight Rain</Title>
<Genre>Fantasy</Genre>
<Price>5.95</Price>
<PublishDate>2000-12-16</PublishDate>
<Description>A former architect battles corporate zombies,
an evil sorceress, and her own childhood to become queen
of the world.</Description>
</Book>
</Catalog>
Preserving White Space while Loading or Parsing
XML
9/3/2020 • 2 minutes to read • Edit Online
This topic describes how to control the white-space behavior of LINQ to XML.
A common scenario is to read indented XML, create an in-memory XML tree without any white space text nodes
(that is, not preserving white space), perform some operations on the XML, and then save the XML with indentation.
When you serialize the XML with formatting, only significant white space in the XML tree is preserved. This is the
default behavior for LINQ to XML.
Another common scenario is to read and modify XML that has already been intentionally indented. You might not
want to change this indentation in any way. To do this in LINQ to XML, you preserve white space when you load or
parse the XML and disable formatting when you serialize the XML.
This topic describes the white-space behavior of methods that populate XML trees. For information about
controlling white space when you serialize XML trees, see Preserving White Space While Serializing.
Example
The following code tries to parse invalid XML:
try {
XElement contacts = XElement.Parse(
@"<Contacts>
<Contact>
<Name>Jim Wilson</Name>
</Contact>
</Contcts>");
Console.WriteLine(contacts);
}
catch (System.Xml.XmlException e)
{
Console.WriteLine(e.Message);
}
The 'Contacts' start tag on line 1 does not match the end tag of 'Contcts'. Line 5, position 13.
For information about the exceptions that you can expect the XElement.Parse, XDocument.Parse, XElement.Load, and
XDocument.Load methods to throw, see the XmlReader documentation.
How to create a tree from an XmlReader (C#)
9/3/2020 • 2 minutes to read • Edit Online
This topic shows how to create an XML tree directly from an XmlReader. To create an XElement from an XmlReader,
you must position the XmlReader on an element node. The XmlReader will skip comments and processing
instructions, but if the XmlReader is positioned on a text node, an error will be thrown. To avoid such errors, always
position the XmlReader on an element before you create an XML tree from the XmlReader.
Example
This example uses the following XML document: Sample XML File: Books (LINQ to XML).
The following code creates an T:System.Xml.XmlReader object, and then reads nodes until it finds the first element
node. It then loads the XElement object.
XmlReader r = XmlReader.Create("books.xml");
while (r.NodeType != XmlNodeType.Element)
r.Read();
XElement e = XElement.Load(r);
Console.WriteLine(e);
<Catalog>
<Book id="bk101">
<Author>Garghentini, Davide</Author>
<Title>XML Developer's Guide</Title>
<Genre>Computer</Genre>
<Price>44.95</Price>
<PublishDate>2000-10-01</PublishDate>
<Description>An in-depth look at creating applications
with XML.</Description>
</Book>
<Book id="bk102">
<Author>Garcia, Debra</Author>
<Title>Midnight Rain</Title>
<Genre>Fantasy</Genre>
<Price>5.95</Price>
<PublishDate>2000-12-16</PublishDate>
<Description>A former architect battles corporate zombies,
an evil sorceress, and her own childhood to become queen
of the world.</Description>
</Book>
</Catalog>
See also
Parsing XML (C#)
How to stream XML fragments from an XmlReader
(C#)
9/3/2020 • 2 minutes to read • Edit Online
When you have to process large XML files, it might not be feasible to load the whole XML tree into memory. This
topic shows how to stream fragments using an XmlReader.
One of the most effective ways to use an XmlReader to read XElement objects is to write your own custom axis
method. An axis method typically returns a collection such as IEnumerable<T> of XElement, as shown in the
example in this topic. In the custom axis method, after you create the XML fragment by calling the ReadFrom
method, return the collection using yield return . This provides deferred execution semantics to your custom axis
method.
When you create an XML tree from an XmlReader object, the XmlReader must be positioned on an element. The
ReadFrom method does not return until it has read the close tag of the element.
If you want to create a partial tree, you can instantiate an XmlReader, position the reader on the node that you want
to convert to an XElement tree, and then create the XElement object.
The topic How to stream XML fragments with access to header information (C#) contains information and an
example on how to stream a more complex document.
The topic How to perform streaming transform of large XML documents (C#) contains an example of using LINQ to
XML to transform extremely large XML documents while maintaining a small memory footprint.
Example
This example creates a custom axis method. You can query it by using a LINQ query. The custom axis method,
StreamRootChildDoc , is a method that is designed specifically to read a document that has a repeating Child
element.
static IEnumerable<XElement> StreamRootChildDoc(StringReader stringReader)
{
using (XmlReader reader = XmlReader.Create(stringReader))
{
reader.MoveToContent();
// Parse the file and display each of the nodes.
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
if (reader.Name == "Child") {
XElement el = XElement.ReadFrom(reader) as XElement;
if (el != null)
yield return el;
}
break;
}
}
}
}
IEnumerable<string> grandChildData =
from el in StreamRootChildDoc(new StringReader(markup))
where (int)el.Attribute("Key") > 1
select (string)el.Element("GrandChild");
bbb
ccc
In this example, the source document is very small. However, even if there were millions of Child elements, this
example would still have a small memory footprint.
How to populate an XML tree with an XmlWriter
(LINQ to XML) (C#)
9/3/2020 • 2 minutes to read • Edit Online
One way to populate an XML tree is to use CreateWriter to create an XmlWriter, and then write to the XmlWriter.
The XML tree is populated with all nodes that are written to the XmlWriter.
You would typically use this method when you use LINQ to XML with another class that expects to write to an
XmlWriter, such as XslCompiledTransform.
Example
One possible use for CreateWriter is when invoking an XSLT transformation. This example creates an XML tree,
creates an XmlReader from the XML tree, creates a new document, and then creates an XmlWriter to write into the
new document. It then invokes the XSLT transformation, passing in XmlReader and XmlWriter. After the
transformation successfully completes, the new XML tree is populated with the results of the transformation.
Console.WriteLine(newTree);
See also
CreateWriter
XmlWriter
XslCompiledTransform
Creating XML Trees (C#)
How to validate using XSD (LINQ to XML) (C#)
9/3/2020 • 2 minutes to read • Edit Online
The System.Xml.Schema namespace contains extension methods that make it easy to validate an XML tree against
an XML Schema Definition Language (XSD) file. For more information, see the Validate method documentation.
Example
The following example creates an XmlSchemaSet, then validates two XDocument objects against the schema set.
One of the documents is valid, the other is not.
string xsdMarkup =
@"<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'>
<xsd:element name='Root'>
<xsd:complexType>
<xsd:sequence>
<xsd:element name='Child1' minOccurs='1' maxOccurs='1'/>
<xsd:element name='Child2' minOccurs='1' maxOccurs='1'/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>";
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add("", XmlReader.Create(new StringReader(xsdMarkup)));
Console.WriteLine("Validating doc1");
bool errors = false;
doc1.Validate(schemas, (o, e) =>
{
Console.WriteLine("{0}", e.Message);
errors = true;
});
Console.WriteLine("doc1 {0}", errors ? "did not validate" : "validated");
Console.WriteLine();
Console.WriteLine("Validating doc2");
errors = false;
doc2.Validate(schemas, (o, e) =>
{
Console.WriteLine("{0}", e.Message);
errors = true;
});
Console.WriteLine("doc2 {0}", errors ? "did not validate" : "validated");
Validating doc2
The element 'Root' has invalid child element 'Child3'. List of possible elements expected: 'Child2'.
doc2 did not validate
Example
The following example validates that the XML document from Sample XML File: Customers and Orders (LINQ to
XML) is valid per the schema from Sample XSD File: Customers and Orders. It then modifies the source XML
document. It changes the CustomerID attribute on the first customer. After the change, orders will then refer to a
customer that does not exist, so the XML document will no longer validate.
This example uses the following XML document: Sample XML File: Customers and Orders (LINQ to XML).
This example uses the following XSD schema: Sample XSD File: Customers and Orders.
Console.WriteLine("Attempting to validate");
XDocument custOrdDoc = XDocument.Load("CustomersOrders.xml");
bool errors = false;
custOrdDoc.Validate(schemas, (o, e) =>
{
Console.WriteLine("{0}", e.Message);
errors = true;
});
Console.WriteLine("custOrdDoc {0}", errors ? "did not validate" : "validated");
Console.WriteLine();
// Modify the source document so that it will not validate.
custOrdDoc.Root.Element("Orders").Element("Order").Element("CustomerID").Value = "AAAAA";
Console.WriteLine("Attempting to validate after modification");
errors = false;
custOrdDoc.Validate(schemas, (o, e) =>
{
Console.WriteLine("{0}", e.Message);
errors = true;
});
Console.WriteLine("custOrdDoc {0}", errors ? "did not validate" : "validated");
Attempting to validate
custOrdDoc validated
See also
Validate
Creating XML Trees (C#)
Valid Content of XElement and XDocument Objects
9/3/2020 • 2 minutes to read • Edit Online
This topic describes the valid arguments that can be passed to constructors and methods that you use to add
content to elements and documents.
Valid Content
Queries often evaluate to IEnumerable<T> of XElement or IEnumerable<T> of XAttribute. You can pass collections
of XElement or XAttribute objects to the XElement constructor. Therefore, it is convenient to pass the results of a
query as content into methods and constructors that you use to populate XML trees.
When adding simple content, various types can be passed to this method. Valid types include the following:
String
Double
Single
Decimal
Boolean
DateTime
TimeSpan
DateTimeOffset
Any type that implements Object.ToString .
Any type that implements IEnumerable<T>.
When adding complex content, various types can be passed to this method:
XObject
XNode
XAttribute
Any type that implements IEnumerable<T>
If an object implements IEnumerable<T>, the collection in the object is enumerated, and all items in the collection
are added. If the collection contains XNode or XAttribute objects, each item in the collection is added separately. If
the collection contains text (or objects that are converted to text), the text in the collection is concatenated and
added as a single text node.
If content is null , nothing is added. When passing a collection items in the collection can be null .A null item in
the collection has no effect on the tree.
An added attribute must have a unique name within its containing element.
When adding XNode or XAttribute objects, if the new content has no parent, then the objects are simply attached to
the XML tree. If the new content already is parented and is part of another XML tree, then the new content is cloned,
and the newly cloned content is attached to the XML tree.
Valid Content for Documents
Attributes and simple content cannot be added to a document.
There are not many scenarios that require you to create an XDocument. Instead, you can usually create your XML
trees with an XElement root node. Unless you have a specific requirement to create a document (for example,
because you have to create processing instructions and comments at the top level, or you have to support
document types), it is often more convenient to use XElement as your root node.
Valid content for a document includes the following:
Zero or one XDocumentType objects. The document types must come before the element.
Zero or one element.
Zero or more comments.
Zero or more processing instructions.
Zero or more text nodes that contain only white space.
M ET H O D DESC RIP T IO N
See also
Creating XML Trees (C#)
Namespaces Overview (LINQ to XML)
9/3/2020 • 2 minutes to read • Edit Online
This article introduces namespaces, the XName class, and the XNamespace class.
XML Names
XML names are often a source of complexity in XML programming. An XML name consists of an XML namespace
(also called an XML namespace URI) and a local name. An XML namespace is similar to a namespace in a .NET
program. It enables you to uniquely qualify the names of elements and attributes. This helps avoid name
conflicts between various parts of an XML document. When you have declared an XML namespace, you can
select a local name that only has to be unique within that namespace.
Another aspect of XML names is XML namespace prefixes. XML prefixes cause most of the complexity of XML
names. These prefixes enable you to create a shortcut for an XML namespace, which makes the XML document
more concise and understandable. However, XML prefixes depend on their context to have meaning, which adds
complexity. For example, the XML prefix aw could be associated with one XML namespace in one part of an XML
tree, and with a different XML namespace in a different part of the XML tree.
One of the advantages of using LINQ to XML with C# is that you do not have to use XML prefixes. When LINQ to
XML loads or parses an XML document, each XML prefix is resolved to its corresponding XML namespace. After
that, when you work with a document that uses namespaces, you almost always access the namespaces through
the namespace URI, and not through the namespace prefix. When developers work with XML names in LINQ to
XML they always work with a fully-qualified XML name (that is, an XML namespace and a local name). However,
when necessary, LINQ to XML allows you to work with and control namespace prefixes.
In LINQ to XML, the class that represents XML names is XName. XML names appear frequently throughout the
LINQ to XML API, and wherever an XML name is required, you will find an XName parameter. However, you
rarely work directly with an XName. XName contains an implicit conversion from string.
For more information, see XNamespace and XName.
How to create a document with namespaces (C#)
(LINQ to XML)
9/3/2020 • 3 minutes to read • Edit Online
Example
To create an element or an attribute that is in a namespace, you first declare and initialize an XNamespace object.
You then use the addition operator overload to combine the namespace with the local name, expressed as a string.
The following example creates a document with one namespace. By default, LINQ to XML serializes this document
with a default namespace.
<Root xmlns="http://www.adventure-works.com">
<Child>child content</Child>
</Root>
Example
The following example creates a document with one namespace. It also creates an attribute that declares the
namespace with a namespace prefix. To create an attribute that declares a namespace with a prefix, you create an
attribute where the name of the attribute is the namespace prefix, and this name is in the Xmlns namespace. The
value of this attribute is the URI of the namespace.
<aw:Root xmlns:aw="http://www.adventure-works.com">
<aw:Child>child content</aw:Child>
</aw:Root>
Example
The following example shows the creation of a document that contains two namespaces. One is the default
namespace. Another is a namespace with a prefix.
By including namespace attributes in the root element, the namespaces are serialized so that
http://www.adventure-works.com is the default namespace, and www.fourthcoffee.com is serialized with a prefix of
"fc". To create an attribute that declares a default namespace, you create an attribute with the name "xmlns", without
a namespace. The value of the attribute is the default namespace URI.
Example
The following example creates a document that contains two namespaces, both with namespace prefixes.
XNamespace aw = "http://www.adventure-works.com";
XNamespace fc = "www.fourthcoffee.com";
XElement root = new XElement(aw + "Root",
new XAttribute(XNamespace.Xmlns + "aw", aw.NamespaceName),
new XAttribute(XNamespace.Xmlns + "fc", fc.NamespaceName),
new XElement(fc + "Child",
new XElement(aw + "DifferentChild", "other content")
),
new XElement(aw + "Child2", "c2 content"),
new XElement(fc + "Child3", "c3 content")
);
Console.WriteLine(root);
<aw:Root xmlns:aw="http://www.adventure-works.com">
<aw:Child>child content</aw:Child>
</aw:Root>
See also
Namespaces Overview (LINQ to XML) (C#)
How to control namespace prefixes (C#) (LINQ to
XML)
9/3/2020 • 2 minutes to read • Edit Online
This topic describes how you can control namespace prefixes when serializing an XML tree.
In many situations, it is not necessary to control namespace prefixes.
However, certain XML programming tools require specific control of namespace prefixes. For example, you might
be manipulating an XSLT style sheet or a XAML document that contains embedded XPath expressions that refer to
specific namespace prefixes; in this case, it is important that the document be serialized with those specific prefixes.
This is the most common reason for controlling namespace prefixes.
Another common reason for controlling namespace prefixes is that you want users to edit the XML document
manually, and you want to create namespace prefixes that are convenient for the user to type. For example, you
might be generating an XSD document. Conventions for schemas suggest that you use either xs or xsd as the
prefix for the schema namespace.
To control namespace prefixes, you insert attributes that declare namespaces. If you declare the namespaces with
specific prefixes, LINQ to XML will attempt to honor the namespace prefixes when serializing.
To create an attribute that declares a namespace with a prefix, you create an attribute where the namespace of the
name of the attribute is Xmlns, and the name of the attribute is the namespace prefix. The value of the attribute is
the URI of the namespace.
Example
This example declares two namespaces. It specifies that the http://www.adventure-works.com namespace has the
prefix of aw , and that the www.fourthcoffee.com namespace has the prefix of fc .
XNamespace aw = "http://www.adventure-works.com";
XNamespace fc = "www.fourthcoffee.com";
XElement root = new XElement(aw + "Root",
new XAttribute(XNamespace.Xmlns + "aw", "http://www.adventure-works.com"),
new XAttribute(XNamespace.Xmlns + "fc", "www.fourthcoffee.com"),
new XElement(fc + "Child",
new XElement(aw + "DifferentChild", "other content")
),
new XElement(aw + "Child2", "c2 content"),
new XElement(fc + "Child3", "c3 content")
);
Console.WriteLine(root);
Default namespaces as represented in the XML tree are not in scope for queries. If you have XML that is in a default
namespace, you still must declare an XNamespace variable, and combine it with the local name to make a qualified
name to be used in the query.
One of the most common problems when querying XML trees is that if the XML tree has a default namespace, the
developer sometimes writes the query as though the XML were not in a namespace.
The first set of examples in this topic shows a typical way that XML in a default namespace is loaded, but is queried
improperly.
The second set of examples show the necessary corrections so that you can query XML in a namespace.
Example
This example shows the creation of XML in a namespace, and a query that returns an empty result set.
Code
Comments
This example produces the following result:
Example
This example shows the creation of XML in a namespace, and a query that is coded properly.
In contrast to the incorrectly coded example above, the correct approach when using C# is to declare and initialize
an XNamespace object, and to use it when specifying XName objects. In this case, the argument to the Elements
method is an XName object.
Code
XElement root = XElement.Parse(
@"<Root xmlns='http://www.adventure-works.com'>
<Child>1</Child>
<Child>2</Child>
<Child>3</Child>
<AnotherChild>4</AnotherChild>
<AnotherChild>5</AnotherChild>
<AnotherChild>6</AnotherChild>
</Root>");
XNamespace aw = "http://www.adventure-works.com";
IEnumerable<XElement> c1 =
from el in root.Elements(aw + "Child")
select el;
Console.WriteLine("Result set follows:");
foreach (XElement el in c1)
Console.WriteLine((int)el);
Console.WriteLine("End of result set");
Comments
This example produces the following result:
See also
Namespaces Overview (LINQ to XML) (C#)
How to write queries on XML in namespaces (C#)
9/3/2020 • 2 minutes to read • Edit Online
To write a query on XML that is in a namespace, you must use XName objects that have the correct namespace.
For C#, the most common approach is to initialize an XNamespace using a string that contains the URI, then use the
addition operator overload to combine the namespace with the local name.
The first set of examples in this topic shows how to create an XML tree in a default namespace. The second set
shows how to create an XML tree in a namespace with a prefix.
Example
The following example creates an XML tree that is in a default namespace. It then retrieves a collection of elements.
XNamespace aw = "http://www.adventure-works.com";
XElement root = XElement.Parse(
@"<Root xmlns='http://www.adventure-works.com'>
<Child>1</Child>
<Child>2</Child>
<Child>3</Child>
<AnotherChild>4</AnotherChild>
<AnotherChild>5</AnotherChild>
<AnotherChild>6</AnotherChild>
</Root>");
IEnumerable<XElement> c1 =
from el in root.Elements(aw + "Child")
select el;
foreach (XElement el in c1)
Console.WriteLine((int)el);
1
2
3
Example
In C#, you write queries in the same way regardless of whether you are writing queries on an XML tree that uses a
namespace with a prefix or on an XML tree with a default namespace.
The following example creates an XML tree that is in a namespace with a prefix. It then retrieves a collection of
elements.
XNamespace aw = "http://www.adventure-works.com";
XElement root = XElement.Parse(
@"<aw:Root xmlns:aw='http://www.adventure-works.com'>
<aw:Child>1</aw:Child>
<aw:Child>2</aw:Child>
<aw:Child>3</aw:Child>
<aw:AnotherChild>4</aw:AnotherChild>
<aw:AnotherChild>5</aw:AnotherChild>
<aw:AnotherChild>6</aw:AnotherChild>
</aw:Root>");
IEnumerable<XElement> c1 =
from el in root.Elements(aw + "Child")
select el;
foreach (XElement el in c1)
Console.WriteLine((int)el);
1
2
3
See also
Namespaces Overview (LINQ to XML) (C#)
Preserving White Space While Serializing
9/3/2020 • 2 minutes to read • Edit Online
This topic describes how to control white space when serializing an XML tree.
A common scenario is to read indented XML, create an in-memory XML tree without any white-space text nodes
(that is, not preserving white space), perform some operations on the XML, and then save the XML with
indentation. When you serialize the XML with formatting, only significant white space in the XML tree is preserved.
This is the default behavior for LINQ to XML.
Another common scenario is to read and modify XML that has already been intentionally indented. You might not
want to change this indentation in any way. To do this in LINQ to XML, you preserve white space when you load or
parse the XML and disable formatting when you serialize the XML.
This topic describes how to control whether serialization generates an XML declaration.
<Root><Child>child content</Child></Root>
See also
Serializing XML Trees (C#)
Serializing to Files, TextWriters, and XmlWriters
9/3/2020 • 2 minutes to read • Edit Online
See also
Serializing XML Trees (C#)
Serializing to an XmlReader (Invoking XSLT) (C#)
9/3/2020 • 2 minutes to read • Edit Online
When you use the System.Xml interoperability capabilities of LINQ to XML, you can use CreateReader to create an
XmlReader. The module that reads from this XmlReader reads the nodes from the XML tree and processes them
accordingly.
Console.WriteLine(newTree);
<Root>
<C1>Child1 data</C1>
<C2>Child2 data</C2>
</Root>
See also
Serializing XML Trees (C#)
LINQ to XML Axes Overview (C#)
9/3/2020 • 3 minutes to read • Edit Online
After you have created an XML tree or loaded an XML document into an XML tree, you can query it to find
elements and attributes and retrieve their values. You retrieve collections through the axis methods, also called
axes. Some of the axes are methods in the XElement and XDocument classes that return IEnumerable<T>
collections. Some of the axes are extension methods in the Extensions class. The axes that are implemented as
extension methods operate on collections, and return collections.
As described in XElement Class Overview, an XElement object represents a single element node. The content of an
element can be complex (sometimes called structured content), or it can be a simple element. A simple element
can be empty or can contain a value. If the node contains structured content, you can use the various axis methods
to retrieve enumerations of descendant elements. The most commonly used axis methods are Elements and
Descendants.
In addition to the axis methods, which return collections, there are two more methods that you will commonly use
in LINQ to XML queries. The Element method returns a single XElement. The Attribute method returns a single
XAttribute.
For many purposes, LINQ queries provide the most powerful way to examine a tree, extract data from it, and
transform it. LINQ queries operate on objects that implement IEnumerable<T>, and the LINQ to XML axes return
IEnumerable<T> of XElement collections, and IEnumerable<T> of XAttribute collections. You need these
collections to perform your queries.
In addition to the axis methods that retrieve collections of elements and attributes, there are axis methods that
allow you to iterate through the tree in great detail. For example, instead of dealing with elements and attributes,
you can work with the nodes of the tree. Nodes are a finer level of granularity than elements and attributes. When
working with nodes, you can examine XML comments, text nodes, processing instructions, and more. This
functionality is important, for example, to someone who is writing a word processor and wants to save
documents as XML. However, the majority of XML programmers are primarily concerned with elements,
attributes, and their values.
M ET H O D DESC RIP T IO N
M ET H O D DESC RIP T IO N
XContainer.Element Returns the first child XElement object that has the specified
XName.
M ET H O D DESC RIP T IO N
M ET H O D DESC RIP T IO N
See also
LINQ to XML Axes (C#)
How to retrieve a collection of elements (LINQ to
XML) (C#)
9/3/2020 • 2 minutes to read • Edit Online
This topic demonstrates the Elements method. This method retrieves a collection of the child elements of an
element.
Example
This example iterates through the child elements of the purchaseOrder element.
This example uses the following XML document: Sample XML File: Typical Purchase Order (LINQ to XML).
XElement po = XElement.Load("PurchaseOrder.xml");
IEnumerable<XElement> childElements =
from el in po.Elements()
select el;
foreach (XElement el in childElements)
Console.WriteLine("Name: " + el.Name);
Name: Address
Name: Address
Name: DeliveryNotes
Name: Items
See also
LINQ to XML Axes (C#)
How to retrieve the value of an element (LINQ to
XML) (C#)
9/3/2020 • 3 minutes to read • Edit Online
This article shows how to get the value of elements. There are two main ways to get the value:
Cast an XElement or an XAttribute to the desired type. The explicit conversion operator then converts the
contents of the element or attribute to the specified type and assigns it to your variable.
Use the XElement.Value or XAttribute.Value properties. You can also set the value using these properties.
With C#, casting is generally the better approach. If you cast the element or attribute to a nullable value type, the
code is simpler to write when retrieving the value of an element (or attribute) that might or might not exist. The last
example in this article demonstrates that casting is simpler in the case where the element might not exist. However,
you cannot set the contents of an element through casting, as you can through XElement.Value property.
<StringElement>abcde</StringElement>
Value of e:abcde
<Age>44</Age>
Value of e:44
LINQ to XML provides explicit cast operators for the following data types: string , bool , bool? , int , int? , uint
, uint? , long , long? , ulong , ulong? , float , float? , double , double? , decimal , decimal? , DateTime ,
DateTime? , TimeSpan , TimeSpan? , GUID , and GUID? .
LINQ to XML provides the same cast operators for XAttribute objects.
Value property example
You can use the Value property to retrieve the contents of an element:
<StringElement>abcde</StringElement>
Value of e:abcde
string c1 = (string)root.Element("Child1");
Console.WriteLine("c1:{0}", c1 == null ? "element does not exist" : c1);
int? c2 = (int?)root.Element("Child2");
Console.WriteLine("c2:{0}", c2 == null ? "element does not exist" : c2.ToString());
string c3 = (string)root.Element("Child3");
Console.WriteLine("c3:{0}", c3 == null ? "element does not exist" : c3);
int? c4 = (int?)root.Element("Child4");
Console.WriteLine("c4:{0}", c4 == null ? "element does not exist" : c4.ToString());
Console.WriteLine();
XElement e1 = root.Element("Child1");
string v1;
if (e1 == null)
v1 = null;
else
v1 = e1.Value;
Console.WriteLine("v1:{0}", v1 == null ? "element does not exist" : v1);
XElement e2 = root.Element("Child2");
int? v2;
if (e2 == null)
v2 = null;
else
v2 = Int32.Parse(e2.Value);
Console.WriteLine("v2:{0}", v2 == null ? "element does not exist" : v2.ToString());
XElement e3 = root.Element("Child3");
string v3;
if (e3 == null)
v3 = null;
else
v3 = e3.Value;
Console.WriteLine("v3:{0}", v3 == null ? "element does not exist" : v3);
XElement e4 = root.Element("Child4");
int? v4;
if (e4 == null)
v4 = null;
else
v4 = Int32.Parse(e4.Value);
Console.WriteLine("v4:{0}", v4 == null ? "element does not exist" : v4.ToString());
v1:child 1 content
v2:2
v3:element does not exist
v4:element does not exist
In general, you can write simpler code when using casting to retrieve the contents of elements and attributes.
See also
LINQ to XML Axes (C#)
How to filter on element names (LINQ to XML) (C#)
9/3/2020 • 2 minutes to read • Edit Online
When you call one of the methods that return IEnumerable<T> of XElement, you can filter on the element name.
Example
This example retrieves a collection of descendants that is filtered to contain only descendants with the specified
name.
This example uses the following XML document: Sample XML File: Typical Purchase Order (LINQ to XML).
XElement po = XElement.Load("PurchaseOrder.xml");
IEnumerable<XElement> items =
from el in po.Descendants("ProductName")
select el;
foreach(XElement prdName in items)
Console.WriteLine(prdName.Name + ":" + (string) prdName);
ProductName:Lawnmower
ProductName:Baby Monitor
The other methods that return IEnumerable<T> of XElement collections follow the same pattern. Their signatures
are similar to Elements and Descendants. The following is the complete list of methods that have similar method
signatures:
Ancestors
Descendants
Elements
ElementsAfterSelf
ElementsBeforeSelf
AncestorsAndSelf
DescendantsAndSelf
Example
The following example shows the same query for XML that is in a namespace. For more information, see
Namespaces Overview (LINQ to XML) (C#).
This example uses the following XML document: Sample XML File: Typical Purchase Order in a Namespace.
XNamespace aw = "http://www.adventure-works.com";
XElement po = XElement.Load("PurchaseOrderInNamespace.xml");
IEnumerable<XElement> items =
from el in po.Descendants(aw + "ProductName")
select el;
foreach (XElement prdName in items)
Console.WriteLine(prdName.Name + ":" + (string)prdName);
{http://www.adventure-works.com}ProductName:Lawnmower
{http://www.adventure-works.com}ProductName:Baby Monitor
See also
LINQ to XML Axes (C#)
How to chain axis method calls (LINQ to XML) (C#)
9/3/2020 • 2 minutes to read • Edit Online
A common pattern that you will use in your code is to call an axis method, then call one of the extension method
axes.
There are two axes with the name of Elements that return a collection of elements: the XContainer.Elements method
and the Extensions.Elements method. You can combine these two axes to find all elements of a specified name at a
given depth in the tree.
Example
This example uses XContainer.Elements and Extensions.Elements to find all Name elements in all Address elements
in all PurchaseOrder elements.
This example uses the following XML document: Sample XML File: Multiple Purchase Orders (LINQ to XML).
<Name>Ellen Adams</Name>
<Name>Tai Yee</Name>
<Name>Cristian Osorio</Name>
<Name>Cristian Osorio</Name>
<Name>Jessica Arnold</Name>
<Name>Jessica Arnold</Name>
This works because one of the implementations of the Elements axis is as an extension method on
IEnumerable<T> of XContainer. XElement derives from XContainer, so you can call the Extensions.Elements method
on the results of a call to the XContainer.Elements method.
Example
Sometimes you want to retrieve all elements at a particular element depth when there might or might not be
intervening ancestors. For example, in the following document, you might want to retrieve all the ConfigParameter
elements that are children of the Customer element, but not the ConfigParameter that is a child of the Root
element.
<Root>
<ConfigParameter>RootConfigParameter</ConfigParameter>
<Customer>
<Name>Frank</Name>
<Config>
<ConfigParameter>FirstConfigParameter</ConfigParameter>
</Config>
</Customer>
<Customer>
<Name>Bob</Name>
<!--This customer doesn't have a Config element-->
</Customer>
<Customer>
<Name>Bill</Name>
<Config>
<ConfigParameter>SecondConfigParameter</ConfigParameter>
</Config>
</Customer>
</Root>
<ConfigParameter>FirstConfigParameter</ConfigParameter>
<ConfigParameter>SecondConfigParameter</ConfigParameter>
Example
The following example shows the same technique for XML that is in a namespace. For more information, see
Namespaces Overview (LINQ to XML) (C#).
This example uses the following XML document: Sample XML File: Multiple Purchase Orders in a Namespace.
XNamespace aw = "http://www.adventure-works.com";
XElement purchaseOrders = XElement.Load("PurchaseOrdersInNamespace.xml");
IEnumerable<XElement> names =
from el in purchaseOrders
.Elements(aw + "PurchaseOrder")
.Elements(aw + "Address")
.Elements(aw + "Name")
select el;
foreach (XElement e in names)
Console.WriteLine(e);
See also
LINQ to XML Axes (C#)
How to retrieve a single child element (LINQ to XML)
(C#)
9/3/2020 • 2 minutes to read • Edit Online
This topic explains how to retrieve a single child element, given the name of the child element. When you know the
name of the child element and that there is only one element that has this name, it can be convenient to retrieve
just one element, instead of a collection.
The Element method returns the first child XElement with the specified XName.
If you want to retrieve a single child element in Visual Basic, a common approach is to use the XML property, and
then retrieve the first element using array indexer notation.
Example
The following example demonstrates the use of the Element method. This example takes the XML tree named po
and finds the first element named Comment .
The Visual Basic example shows using array indexer notation to retrieve a single element.
This example uses the following XML document: Sample XML File: Typical Purchase Order (LINQ to XML).
XElement po = XElement.Load("PurchaseOrder.xml");
XElement e = po.Element("DeliveryNotes");
Console.WriteLine(e);
Example
The following example shows the same code for XML that is in a namespace. For more information, see
Namespaces Overview (LINQ to XML) (C#).
This example uses the following XML document: Sample XML File: Typical Purchase Order in a Namespace.
XElement po = XElement.Load("PurchaseOrderInNamespace.xml");
XNamespace aw = "http://www.adventure-works.com";
XElement e = po.Element(aw + "DeliveryNotes");
Console.WriteLine(e);
See also
LINQ to XML Axes (C#)
How to retrieve a collection of attributes (LINQ to
XML) (C#)
9/3/2020 • 2 minutes to read • Edit Online
This topic introduces the Attributes method. This method retrieves the attributes of an element.
Example
The following example shows how to iterate through the collection of attributes of an element.
ID="1243"
Type="int"
ConvertableTo="double"
See also
LINQ to XML Axes (C#)
How to retrieve a single attribute (LINQ to XML) (C#)
9/3/2020 • 2 minutes to read • Edit Online
This topic explains how to retrieve a single attribute of an element, given the attribute name. This is useful for
writing query expressions where you want to find an element that has a particular attribute.
The Attribute method of the XElement class returns the XAttribute with the specified name.
Example
The following example uses the Attribute method.
This example finds all the descendants in the tree named Phone , and then finds the attribute named type .
This code produces the following output:
home
work
Example
If you want to retrieve the value of the attribute, you can cast it, just as you do for with XElement objects. The
following example demonstrates this.
LINQ to XML provides explicit cast operators for the XAttribute class to string , bool , bool? , int , int? , uint ,
uint? , long , long? , ulong , ulong? , float , float? , double , double? , decimal , decimal? , DateTime ,
DateTime? , TimeSpan , TimeSpan? , GUID , and GUID? .
Example
The following example shows the same code for an attribute that is in a namespace. For more information, see
Namespaces Overview (LINQ to XML) (C#).
XNamespace aw = "http://www.adventure-works.com";
XElement cust = new XElement(aw + "PhoneNumbers",
new XElement(aw + "Phone",
new XAttribute(aw + "type", "home"),
"555-555-5555"),
new XElement(aw + "Phone",
new XAttribute(aw + "type", "work"),
"555-555-6666")
);
IEnumerable<XElement> elList =
from el in cust.Descendants(aw + "Phone")
select el;
foreach (XElement el in elList)
Console.WriteLine((string)el.Attribute(aw + "type"));
home
work
See also
LINQ to XML Axes (C#)
How to retrieve the value of an attribute (LINQ to
XML) (C#)
9/3/2020 • 2 minutes to read • Edit Online
This topic shows how to obtain the value of attributes. There are two main ways: You can cast an XAttribute to the
desired type; the explicit conversion operator then converts the contents of the element or attribute to the specified
type. Alternatively, you can use the Value property. However, casting is generally the better approach. If you cast the
attribute to a nullable value type, the code is simpler to write when retrieving the value of an attribute that might or
might not exist. For examples of this technique, see How to retrieve the value of an element (LINQ to XML) (C#).
Example
To retrieve the value of an attribute, you just cast the XAttribute object to your desired type.
Example
The following example shows how to retrieve the value of an attribute where the attribute is in a namespace. For
more information, see Namespaces Overview (LINQ to XML) (C#).
XNamespace aw = "http://www.adventure-works.com";
XElement root = new XElement(aw + "Root",
new XAttribute(aw + "Attr", "abcde")
);
string str = (string)root.Attribute(aw + "Attr");
Console.WriteLine(str);
abcde
See also
LINQ to XML Axes (C#)
How to retrieve the shallow value of an element (C#)
9/3/2020 • 2 minutes to read • Edit Online
This topic shows how to get the shallow value of an element. The shallow value is the value of the specific element
only, as opposed to the deep value, which includes the values of all descendent elements concatenated into a single
string.
When you retrieve an element value by using either casting or the XElement.Value property, you retrieve the deep
value. To retrieve the shallow value, you can use the ShallowValue extension method, as shown in the following
example. Retrieving the shallow value is useful when you want to select elements based on their content.
The following example declares an extension method that retrieves the shallow value of an element. It then uses the
extension method in a query to list all elements that contain a calculated value.
Example
The following text file, Report.xml, is the source for this example.
class Program
{
static void Main(string[] args)
{
XElement root = XElement.Load("Report.xml");
See also
LINQ to XML Axes (C#)
How to find an element with a specific attribute (C#)
9/3/2020 • 2 minutes to read • Edit Online
This topic shows how to find an element that has an attribute that has a specific value.
Example
The example shows how to find the Address element that has a Type attribute with a value of "Billing".
This example uses the following XML document: Sample XML File: Typical Purchase Order (LINQ to XML).
<Address Type="Billing">
<Name>Tai Yee</Name>
<Street>8 Oak Avenue</Street>
<City>Old Town</City>
<State>PA</State>
<Zip>95819</Zip>
<Country>USA</Country>
</Address>
Example
The following example shows the same query for XML that is in a namespace. For more information, see
Namespaces Overview (LINQ to XML) (C#).
This example uses the following XML document: Sample XML File: Typical Purchase Order in a Namespace.
See also
Attribute
Elements
Standard Query Operators Overview (C#)
Projection Operations (C#)
How to find an element with a specific child element
(C#)
9/3/2020 • 2 minutes to read • Edit Online
This topic shows how to find a particular element that has a child element with a specific value.
Example
The example finds the Test element that has a CommandLine child element with the value of "Examp2.EXE".
This example uses the following XML document: Sample XML File: Test Configuration (LINQ to XML).
0002
0006
Example
The following example shows the same query for XML that is in a namespace. For more information, see
Namespaces Overview (LINQ to XML) (C#).
This example uses the following XML document: Sample XML File: Test Configuration in a Namespace.
0002
0006
See also
Attribute
Elements
Standard Query Operators Overview (C#)
Projection Operations (C#)
Querying an XDocument vs. Querying an XElement
(C#)
9/3/2020 • 2 minutes to read • Edit Online
When you load a document via XDocument.Load, you will notice that you have to write queries slightly differently
than when you load via XElement.Load.
The following example is the same as the one above, with the exception that the XML tree is loaded into an
XDocument instead of an XElement.
// Create a simple document and write it to a file
File.WriteAllText("Test.xml", @"<Root>
<Child1>1</Child1>
<Child2>2</Child2>
<Child3>3</Child3>
</Root>");
Notice that the same query returned the one Root node instead of the three child nodes.
One approach to dealing with this is to use the Root property before accessing the axes methods, as follows:
This query now performs in the same way as the query on the tree rooted in XElement. The example produces the
following output:
Sometimes you want to find all descendants with a particular name. You could write code to iterate through all of
the descendants, but it is easier to use the Descendants axis.
Example
The following example shows how to find descendants based on the element name.
Console.WriteLine(str);
Example
The following example shows the same query for XML that is in a namespace. For more information, see
Namespaces Overview (LINQ to XML) (C#).
XElement root = XElement.Parse(@"<root xmlns='http://www.adatum.com'>
<para>
<r>
<t>Some text </t>
</r>
<n>
<r>
<t>that is broken up into </t>
</r>
</n>
<n>
<r>
<t>multiple segments.</t>
</r>
</n>
</para>
</root>");
XNamespace ad = "http://www.adatum.com";
IEnumerable<string> textSegs =
from seg in root.Descendants(ad + "t")
select (string)seg;
Console.WriteLine(str);
See also
Descendants
How to find a single descendant using the
descendants method (C#)
9/3/2020 • 2 minutes to read • Edit Online
You can use the Descendants axis method to quickly write code to find a single uniquely named element. This
technique is especially useful when you want to find a particular descendant with a specific name. You could write
the code to navigate to the desired element, but it is often faster and easier to write the code using the Descendants
axis.
Example
This example uses the First standard query operator.
GC3 Value
Example
The following example shows the same query for XML that is in a namespace. For more information, see
Namespaces Overview (LINQ to XML) (C#).
XElement root = XElement.Parse(@"<aw:Root xmlns:aw='http://www.adventure-works.com'>
<aw:Child1>
<aw:GrandChild1>GC1 Value</aw:GrandChild1>
</aw:Child1>
<aw:Child2>
<aw:GrandChild2>GC2 Value</aw:GrandChild2>
</aw:Child2>
<aw:Child3>
<aw:GrandChild3>GC3 Value</aw:GrandChild3>
</aw:Child3>
<aw:Child4>
<aw:GrandChild4>GC4 Value</aw:GrandChild4>
</aw:Child4>
</aw:Root>");
XNamespace aw = "http://www.adventure-works.com";
string grandChild3 = (string)
(from el in root.Descendants(aw + "GrandChild3")
select el).First();
Console.WriteLine(grandChild3);
GC3 Value
How to write queries with complex filtering (C#)
9/3/2020 • 2 minutes to read • Edit Online
Sometimes you want to write LINQ to XML queries with complex filters. For example, you might have to find all
elements that have a child element with a particular name and value. This topic gives an example of writing a query
with complex filtering.
Example
This example shows how to find all PurchaseOrder elements that have a child Address element that has a Type
attribute equal to "Shipping" and a child State element equal to "NY". It uses a nested query in the Where clause,
and the Any operator returns true if the collection has any elements in it. For information about using method-
based query syntax, see Query Syntax and Method Syntax in LINQ.
This example uses the following XML document: Sample XML File: Multiple Purchase Orders (LINQ to XML).
For more information about the Any operator, see Quantifier Operations (C#).
99505
Example
The following example shows the same query for XML that is in a namespace. For more information, see
Namespaces Overview (LINQ to XML) (C#).
This example uses the following XML document: Sample XML File: Multiple Purchase Orders in a Namespace.
XElement root = XElement.Load("PurchaseOrdersInNamespace.xml");
XNamespace aw = "http://www.adventure-works.com";
IEnumerable<XElement> purchaseOrders =
from el in root.Elements(aw + "PurchaseOrder")
where
(from add in el.Elements(aw + "Address")
where
(string)add.Attribute(aw + "Type") == "Shipping" &&
(string)add.Element(aw + "State") == "NY"
select add)
.Any()
select el;
foreach (XElement el in purchaseOrders)
Console.WriteLine((string)el.Attribute(aw + "PurchaseOrderNumber"));
99505
See also
Attribute
Elements
Projection Operations (C#)
Quantifier Operations (C#)
How to filter on an optional element (C#)
9/3/2020 • 2 minutes to read • Edit Online
Sometimes you want to filter for an element even though you are not sure it exists in your XML document. The
search should be executed so that if the particular element does not have the child element, you do not trigger a
null reference exception by filtering for it. In the following example, the Child5 element does not have a Type child
element, but the query still executes correctly.
Example
This example uses the Elements extension method.
Example
The following example shows the same query for XML that is in a namespace. For more information, see
Namespaces Overview (LINQ to XML) (C#).
XElement root = XElement.Parse(@"<Root xmlns='http://www.adatum.com'>
<Child1>
<Text>Child One Text</Text>
<Type Value=""Yes""/>
</Child1>
<Child2>
<Text>Child Two Text</Text>
<Type Value=""Yes""/>
</Child2>
<Child3>
<Text>Child Three Text</Text>
<Type Value=""No""/>
</Child3>
<Child4>
<Text>Child Four Text</Text>
<Type Value=""Yes""/>
</Child4>
<Child5>
<Text>Child Five Text</Text>
</Child5>
</Root>");
XNamespace ad = "http://www.adatum.com";
var cList =
from typeElement in root.Elements().Elements(ad + "Type")
where (string)typeElement.Attribute("Value") == "Yes"
select (string)typeElement.Parent.Element(ad + "Text");
foreach (string str in cList)
Console.WriteLine(str);
See also
XElement.Attribute
XContainer.Elements
Extensions.Elements
Standard Query Operators Overview (C#)
Projection Operations (C#)
How to find all nodes in a namespace (C#)
9/3/2020 • 2 minutes to read • Edit Online
You can filter on the namespace of each element or attribute to find all nodes in that particular namespace.
Example
The following example creates an XML tree with two namespaces. It then iterates through the tree and prints the
names of all the elements and attributes in one of those namespaces.
Example
The XML file accessed by the following query contains purchase orders in two different namespaces. The query
creates a new tree with just the elements in one of the namespaces.
This example uses the following XML document: Sample XML File: Consolidated Purchase Orders.
This example shows how to write a query that sorts its results.
Example
This example uses the following XML document: Sample XML File: Numerical Data (LINQ to XML).
0.99
4.95
6.99
24.50
29.00
66.00
89.99
Example
The following example shows the same query for XML that is in a namespace. For more information, see
Namespaces Overview (LINQ to XML) (C#).
This example uses the following XML document: Sample XML File: Numerical Data in a Namespace.
See also
Sorting Data (C#)
How to sort elements on multiple keys (C#)
9/3/2020 • 2 minutes to read • Edit Online
Example
In this example, the results are ordered first by the shipping postal code, then by the order date.
This example uses the following XML document: Sample XML File: Customers and Orders (LINQ to XML).
XElement co = XElement.Load("CustomersOrders.xml");
var sortedElements =
from c in co.Element("Orders").Elements("Order")
orderby (string)c.Element("ShipInfo").Element("ShipPostalCode"),
(DateTime)c.Element("OrderDate")
select new {
CustomerID = (string)c.Element("CustomerID"),
EmployeeID = (string)c.Element("EmployeeID"),
ShipPostalCode = (string)c.Element("ShipInfo").Element("ShipPostalCode"),
OrderDate = (DateTime)c.Element("OrderDate")
};
foreach (var r in sortedElements)
Console.WriteLine("CustomerID:{0} EmployeeID:{1} ShipPostalCode:{2} OrderDate:{3:d}",
r.CustomerID, r.EmployeeID, r.ShipPostalCode, r.OrderDate);
Example
The following example shows the same query for XML that is in a namespace. For more information, see
Namespaces Overview (LINQ to XML) (C#).
This example uses the following XML document: Sample XML File: Customers and Orders in a Namespace.
XElement co = XElement.Load("CustomersOrdersInNamespace.xml");
XNamespace aw = "http://www.adventure-works.com";
var sortedElements =
from c in co.Element(aw + "Orders").Elements(aw + "Order")
orderby (string)c.Element(aw + "ShipInfo").Element(aw + "ShipPostalCode"),
(DateTime)c.Element(aw + "OrderDate")
select new
{
CustomerID = (string)c.Element(aw + "CustomerID"),
EmployeeID = (string)c.Element(aw + "EmployeeID"),
ShipPostalCode = (string)c.Element(aw + "ShipInfo").Element(aw + "ShipPostalCode"),
OrderDate = (DateTime)c.Element(aw + "OrderDate")
};
foreach (var r in sortedElements)
Console.WriteLine("CustomerID:{0} EmployeeID:{1} ShipPostalCode:{2} OrderDate:{3:d}",
r.CustomerID, r.EmployeeID, r.ShipPostalCode, r.OrderDate);
This example shows how to calculate intermediate values that can be used in sorting, filtering, and selecting.
Example
The following example uses the Let clause.
This example uses the following XML document: Sample XML File: Numerical Data (LINQ to XML).
55.92
73.50
89.99
198.00
435.00
Example
The following example shows the same query for XML that is in a namespace. For more information, see
Namespaces Overview (LINQ to XML) (C#).
This example uses the following XML document: Sample XML File: Numerical Data in a Namespace.
Sometimes you might have to write a query that selects elements based on their context. You might want to filter
based on preceding or following sibling elements. You might want to filter based on child or ancestor elements.
You can do this by writing a query and using the results of the query in the where clause. If you have to first test
against null, and then test the value, it is more convenient to do the query in a let clause, and then use the results
in the where clause.
Example
The following example selects all p elements that are immediately followed by a ul element.
IEnumerable<XElement> items =
from e in doc.Descendants("p")
let z = e.ElementsAfterSelf().FirstOrDefault()
where z != null && z.Name.LocalName == "ul"
select e;
id = 1
id = 3
id = 6
Example
The following example shows the same query for XML that is in a namespace. For more information, see
Namespaces Overview (LINQ to XML) (C#).
XElement doc = XElement.Parse(@"<Root xmlns='http://www.adatum.com'>
<p id=""1""/>
<ul>abc</ul>
<Child>
<p id=""2""/>
<notul/>
<p id=""3""/>
<ul>def</ul>
<p id=""4""/>
</Child>
<Child>
<p id=""5""/>
<notul/>
<p id=""6""/>
<ul>abc</ul>
<p id=""7""/>
</Child>
</Root>");
XNamespace ad = "http://www.adatum.com";
IEnumerable<XElement> items =
from e in doc.Descendants(ad + "p")
let z = e.ElementsAfterSelf().FirstOrDefault()
where z != null && z.Name == ad.GetName("ul")
select e;
id = 1
id = 3
id = 6
See also
Parse
Descendants
ElementsAfterSelf
FirstOrDefault
How to debug empty query results sets (C#)
9/3/2020 • 2 minutes to read • Edit Online
One of the most common problems when querying XML trees is that if the XML tree has a default namespace, the
developer sometimes writes the query as though the XML were not in a namespace.
The first set of examples in this topic shows a typical way that XML in a default namespace is loaded, and is queried
improperly.
The second set of examples show the necessary corrections so that you can query XML in a namespace.
For more information, see Namespaces Overview (LINQ to XML) (C#).
Example
This example shows creation of XML in a namespace, and a query that returns an empty result set.
Example
This example shows creation of XML in a namespace, and a query that is coded properly.
The solution is to declare and initialize an XNamespace object, and to use it when specifying XName objects. In this
case, the argument to the Elements method is an XName object.
XElement root = XElement.Parse(
@"<Root xmlns='http://www.adventure-works.com'>
<Child>1</Child>
<Child>2</Child>
<Child>3</Child>
<AnotherChild>4</AnotherChild>
<AnotherChild>5</AnotherChild>
<AnotherChild>6</AnotherChild>
</Root>");
XNamespace aw = "http://www.adventure-works.com";
IEnumerable<XElement> c1 =
from el in root.Elements(aw + "Child")
select el;
Console.WriteLine("Result set follows:");
foreach (XElement el in c1)
Console.WriteLine((int)el);
Console.WriteLine("End of result set");
It is often convenient to convert varieties of data structures to XML, and XML back to other data structures. This
topic shows a specific implementation of this general approach by converting a Dictionary<TKey,TValue> to XML
and back.
Example
This example uses a form of functional construction in which a query projects new XElement objects, and the
resulting collection is passed as an argument to the constructor of the Root XElement object.
<Root>
<Child1>Value1</Child1>
<Child2>Value2</Child2>
<Child3>Value3</Child3>
<Child4>Value4</Child4>
</Root>
Example
The following code creates a dictionary from XML.
The shape of an XML document refers to its element names, attribute names, and the characteristics of its hierarchy.
Sometimes you will have to change the shape of an XML document. For example, you might have to send an
existing XML document to another system that requires different element and attribute names. You could go
through the document, deleting and renaming elements as required, but using functional construction results in
more readable and maintainable code. For more information about functional construction, see Functional
Construction (LINQ to XML) (C#).
The first example changes the organization of the XML document. It moves complex elements from one location in
the tree to another.
The second example in this topic creates an XML document with a different shape than the source document. It
changes the casing of the element names, renames some elements, and leaves some elements from the source tree
out of the transformed tree.
Example
The following code changes the shape of an XML file using embedded query expressions.
The source XML document in this example contains a Customers element under the Root element that contains all
customers. It also contains an Orders element under the Root element that contains all orders. This example
creates a new XML tree in which the orders for each customer are contained in an Orders element within the
Customer element. The original document also contains a CustomerID element in the Order element; this element
will be removed from the re-shaped document.
This example uses the following XML document: Sample XML File: Customers and Orders (LINQ to XML).
XElement co = XElement.Load("CustomersOrders.xml");
XElement newCustOrd =
new XElement("Root",
from cust in co.Element("Customers").Elements("Customer")
select new XElement("Customer",
cust.Attributes(),
cust.Elements(),
new XElement("Orders",
from ord in co.Element("Orders").Elements("Order")
where (string)ord.Element("CustomerID") == (string)cust.Attribute("CustomerID")
select new XElement("Order",
ord.Attributes(),
ord.Element("EmployeeID"),
ord.Element("OrderDate"),
ord.Element("RequiredDate"),
ord.Element("ShipInfo")
)
)
)
);
Console.WriteLine(newCustOrd);
Example
This example renames some elements and converts some attributes to elements.
The code calls ConvertAddress , which returns a list of XElement objects. The argument to the method is a query that
determines the Address complex element where the Type attribute has a value of "Shipping" .
This example uses the following XML document: Sample XML File: Typical Purchase Order (LINQ to XML).
static IEnumerable<XElement> ConvertAddress(XElement add)
{
List<XElement> fragment = new List<XElement>() {
new XElement("NAME", (string)add.Element("Name")),
new XElement("STREET", (string)add.Element("Street")),
new XElement("CITY", (string)add.Element("City")),
new XElement("ST", (string)add.Element("State")),
new XElement("POSTALCODE", (string)add.Element("Zip")),
new XElement("COUNTRY", (string)add.Element("Country"))
};
return fragment;
}
<PO>
<ID>99503</ID>
<DATE>1999-10-20T00:00:00</DATE>
<NAME>Ellen Adams</NAME>
<STREET>123 Maple Street</STREET>
<CITY>Mill Valley</CITY>
<ST>CA</ST>
<POSTALCODE>10999</POSTALCODE>
<COUNTRY>USA</COUNTRY>
</PO>
How to control the type of a projection (C#)
9/3/2020 • 2 minutes to read • Edit Online
Projection is the process of taking one set of data, filtering it, changing its shape, and even changing its type. Most
query expressions perform projections. Most of the query expressions shown in this section evaluate to
IEnumerable<T> of XElement, but you can control the type of the projection to create collections of other types.
This topic shows how to do this.
Example
The following example defines a new type, Customer . The query expression then instantiates new Customer objects
in the Select clause. This causes the type of the query expression to be IEnumerable<T> of Customer .
This example uses the following XML document: Sample XML File: Customers and Orders (LINQ to XML).
class Program
{
static void Main(string[] args)
{
XElement custOrd = XElement.Load("CustomersOrders.xml");
IEnumerable<Customer> custList =
from el in custOrd.Element("Customers").Elements("Customer")
select new Customer(
(string)el.Attribute("CustomerID"),
(string)el.Element("CompanyName"),
(string)el.Element("ContactName")
);
foreach (Customer cust in custList)
Console.WriteLine(cust);
}
}
See also
Select
How to project a new type (LINQ to XML) (C#)
9/3/2020 • 2 minutes to read • Edit Online
Other examples in this section have shown queries that return results as IEnumerable<T> of XElement,
IEnumerable<T> of string , and IEnumerable<T> of int . These are common result types, but they are not
appropriate for every scenario. In many cases you will want your queries to return an IEnumerable<T> of some
other type.
Example
This example shows how to instantiate objects in the select clause. The code first defines a new class with a
constructor, and then modifies the select statement so that the expression is a new instance of the new class.
This example uses the following XML document: Sample XML File: Typical Purchase Order (LINQ to XML).
class NameQty
{
public string name;
public int qty;
public NameQty(string n, int q)
{
name = n;
qty = q;
}
};
class Program {
public static void Main()
{
XElement po = XElement.Load("PurchaseOrder.xml");
IEnumerable<NameQty> nqList =
from n in po.Descendants("Item")
select new NameQty(
(string)n.Element("ProductName"),
(int)n.Element("Quantity")
);
This example uses the Element method that was introduced in the topic How to retrieve a single child element
(LINQ to XML) (C#). It also uses casts to retrieve the values of the elements that are returned by the Element
method.
This example produces the following output:
Lawnmower:1
Baby Monitor:2
How to project an object graph (C#)
9/3/2020 • 3 minutes to read • Edit Online
This topic illustrates how to project, or populate, an object graph from XML.
Example
The following code populates an object graph with the Address , PurchaseOrder , and PurchaseOrderItem classes
from the Sample XML File: Typical Purchase Order (LINQ to XML) XML document.
class Address
{
public enum AddressUse
{
Shipping,
Billing,
}
class PurchaseOrderItem
{
private string partNumber;
private string productName;
private int quantity;
private Decimal usPrice;
private string comment;
private DateTime shipDate;
class PurchaseOrder
{
private string purchaseOrderNumber;
private DateTime orderDate;
private string comment;
private List<Address> addresses;
private List<PurchaseOrderItem> items;
class Program {
public static void Main()
{
XElement po = XElement.Load("PurchaseOrder.xml");
PurchaseOrder purchaseOrder = new PurchaseOrder {
PurchaseOrderNumber = (string)po.Attribute("PurchaseOrderNumber"),
OrderDate = (DateTime)po.Attribute("OrderDate"),
Addresses = (
from a in po.Elements("Address")
select new Address {
AddressType = ((string)a.Attribute("Type") == "Shipping") ?
Address.AddressUse.Shipping :
Address.AddressUse.Billing,
Name = (string)a.Element("Name"),
Street = (string)a.Element("Street"),
City = (string)a.Element("City"),
State = (string)a.Element("State"),
Zip = (string)a.Element("Zip"),
Country = (string)a.Element("Country")
}
).ToList(),
Items = (
from i in po.Element("Items").Elements("Item")
select new PurchaseOrderItem {
PartNumber = (string)i.Attribute("PartNumber"),
ProductName = (string)i.Element("ProductName"),
Quantity = (int)i.Element("Quantity"),
USPrice = (Decimal)i.Element("USPrice"),
Comment = (string)i.Element("Comment"),
ShipDate = (i.Element("ShipDate") != null) ?
(DateTime)i.Element("ShipDate") :
(DateTime)i.Element("ShipDate") :
DateTime.MinValue
}
).ToList()
};
Console.WriteLine(purchaseOrder);
}
}
In this example, the result of the LINQ query is returned as an IEnumerable<T> of PurchaseOrderItem . The items in
the PurchaseOrder class are of type IEnumerable<T> of PurchaseOrderItem . The code uses the ToList extension
method to create a List<T> collection from the results of the query.
The example produces the following output:
PurchaseOrderNumber: 99503
OrderDate: 10/20/1999
Addresses
=====
Type: Shipping
Name: Ellen Adams
Street: 123 Maple Street
City: Mill Valley
State: CA
Zip: 10999
Country: USA
Type: Billing
Name: Tai Yee
Street: 8 Oak Avenue
City: Old Town
State: PA
Zip: 95819
Country: USA
Items
=====
PartNumber: 872-AA
ProductName: Lawnmower
Quantity: 1
USPrice: 148.95
Comment: Confirm this is electric
PartNumber: 926-AA
ProductName: Baby Monitor
Quantity: 2
USPrice: 39.98
ShipDate: 5/21/1999
See also
Select
ToList
How to project an anonymous type (C#)
9/3/2020 • 2 minutes to read • Edit Online
In some cases you might want to project a query to a new type, even though you know you will only use this type
for a short while. It is a lot of extra work to create a new type just to use in the projection. A more efficient approach
in this case is to project to an anonymous type. Anonymous types allow you to define a class, then declare and
initialize an object of that class, without giving the class a name.
Anonymous types are the C# implementation of the mathematical concept of a tuple. The mathematical term tuple
originated from the sequence single, double, triple, quadruple, quintuple, n-tuple. It refers to a finite sequence of
objects, each of a specific type. Sometimes this is called a list of name/value pairs. For example, the contents of an
address in the Sample XML File: Typical Purchase Order (LINQ to XML) XML document could be expressed as
follows:
When you create an instance of an anonymous type, it is convenient to think of it as creating a tuple of order n. If
you write a query that creates a tuple in the select clause, the query returns an IEnumerable of the tuple.
Example
In this example, the select clause projects an anonymous type. The example then uses var to create the
IEnumerable object. Within the foreach loop, the iteration variable becomes an instance of the anonymous type
created in the query expression.
This example uses the following XML document: Sample XML File: Customers and Orders (LINQ to XML).
This example shows how to generate a comma-separated values (CSV) file from an XML file.
Example
The C# version of this example uses method syntax and the Aggregate operator to generate a CSV file from an XML
document in a single expression. For more information, see Query Syntax and Method Syntax in LINQ.
This example uses the following XML document: Sample XML File: Customers and Orders (LINQ to XML).
See also
Projections and Transformations (LINQ to XML) (C#)
How to generate XML from CSV files (C#)
9/3/2020 • 2 minutes to read • Edit Online
This example shows how to use Language-Integrated Query (LINQ) and LINQ to XML to generate an XML file from
a comma-separated value (CSV) file.
Example
The following code performs a LINQ query on an array of strings.
The query uses the let clause to split each string into an array of fields.
An element or attribute in an XML document can sometimes refer to another element or attribute. For example, the
Sample XML File: Customers and Orders (LINQ to XML) XML document contains a list of customers and a list of
orders. Each Customer element contains a CustomerID attribute. Each Order element contains a CustomerID
element. The CustomerID element in each order refers to the CustomerID attribute in a customer.
The topic Sample XSD File: Customers and Orders contains an XSD that can be used to validate this document. It
uses the xs:key and xs:keyref features of XSD to establish that the CustomerID attribute of the Customer
element is a key, and to establish a relationship between the CustomerID element in each Order element and the
CustomerID attribute in each Customer element.
With LINQ to XML, you can take advantage of this relationship by using the join clause.
Because there is no index available, such joining will have poor run-time performance.
For more detailed information about join , see Join Operations (C#).
Example
The following example joins the Customer elements to the Order elements, and generates a new XML document
that includes the CompanyName element in the orders.
Before executing the query, the example validates that the document complies with the schema in Sample XSD File:
Customers and Orders. This ensures that the join clause will always work.
This query first retrieves all Customer elements, and then joins them to the Order elements. It selects only the
orders for customers with a CustomerID greater than "K". It then projects a new Order element that contains the
customer information within each order.
This example uses the following XML document: Sample XML File: Customers and Orders (LINQ to XML).
This example uses the following XSD schema: Sample XSD File: Customers and Orders.
Joining in this fashion will not perform well. Joins are performed via a linear search. There are no hash tables or
indexes to help with performance.
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add("", "CustomersOrders.xsd");
if (!errors)
{
// Join customers and orders, and create a new XML document with
// a different shape.
This example shows how to group data, and then generate XML based on the grouping.
Example
This example first groups data by a category, then generates a new XML file in which the XML hierarchy reflects the
grouping.
This example uses the following XML document: Sample XML File: Numerical Data (LINQ to XML).
This topic introduces the extension methods that enable you to query an XML tree by using XPath. For detailed
information about using these extension methods, see System.Xml.XPath.Extensions.
Unless you have a very specific reason for querying using XPath, such as extensive use of legacy code, using XPath
with LINQ to XML is not recommended. XPath queries will not perform as well as LINQ to XML queries.
Example
The following example creates a small XML tree and uses XPathSelectElements to select a set of elements.
<Child2>4</Child2>
<Child2>5</Child2>
<Child2>6</Child2>
How to write a LINQ to XML axis method (C#)
9/3/2020 • 3 minutes to read • Edit Online
An XML axis method retrieves a collection of XML elements from an XML document or ancestor element. You can
write your own axis methods to retrieve collections from an XML tree. One of the best ways to do this is to write an
extension method that returns a collection of elements or attributes. You can write your extension method to return
specific subsets of elements or attributes, based on the requirements of your application.
Example
The following example uses two extension methods. The first extension method, GetXPath , operates on XObject,
and returns an XPath expression that when evaluated will return the node or attribute. The second extension
method, Find , operates on XElement. It returns a collection of XAttribute objects and XElement objects that contain
some specified text.
This example uses the following XML document: Sample XML File: Multiple Purchase Orders (LINQ to XML).
class Program
{
static void Main(string[] args)
{
XElement purchaseOrders = XElement.Load("PurchaseOrders.xml");
IEnumerable<XObject> subset =
from xobj in purchaseOrders.Find("1999")
select xobj;
/PurchaseOrders/PurchaseOrder[1]/@OrderDate
1999-10-20
/PurchaseOrders/PurchaseOrder[1]/Items/Item[2]/ShipDate
1999-05-21
/PurchaseOrders/PurchaseOrder[2]/@OrderDate
1999-10-22
/PurchaseOrders/PurchaseOrder[3]/@OrderDate
1999-10-22
How to perform streaming transformations of text to
XML (C#)
9/3/2020 • 2 minutes to read • Edit Online
One approach to processing a text file is to write an extension method that streams the text file a line at a time using
the yield return construct. You then can write a LINQ query that processes the text file in a lazy deferred fashion. If
you then use XStreamingElement to stream output, you then can create a transformation from the text file to XML
that uses a minimal amount of memory, regardless of the size of the source text file.
There are some caveats regarding streaming transformations. A streaming transformation is best applied in
situations where you can process the entire file once, and if you can process the lines in the order that they occur in
the source document. If you have to process the file more than once, or if you have to sort the lines before you can
process them, you will lose many of the benefits of using a streaming technique.
Example
The following text file, People.txt, is the source for this example.
#This is a comment
1,Tai,Yee,Writer
2,Nikolay,Grachev,Programmer
3,David,Wright,Inventor
The following code contains an extension method that streams the lines of the text file in a deferred fashion.
public static class StreamReaderSequence
{
public static IEnumerable<string> Lines(this StreamReader source)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
string line;
while ((line = source.ReadLine()) != null)
{
yield return line;
}
}
}
class Program
{
static void Main(string[] args)
{
var sr = new StreamReader("People.txt");
var xmlTree = new XStreamingElement("Root",
from line in sr.Lines()
let items = line.Split(',')
where !line.StartsWith("#")
select new XElement("Person",
new XAttribute("ID", items[0]),
new XElement("First", items[1]),
new XElement("Last", items[2]),
new XElement("Occupation", items[3])
)
);
Console.WriteLine(xmlTree);
sr.Close();
}
}
<Root>
<Person ID="1">
<First>Tai</First>
<Last>Yee</Last>
<Occupation>Writer</Occupation>
</Person>
<Person ID="2">
<First>Nikolay</First>
<Last>Grachev</Last>
<Occupation>Programmer</Occupation>
</Person>
<Person ID="3">
<First>David</First>
<Last>Wright</Last>
<Occupation>Inventor</Occupation>
</Person>
</Root>
See also
XStreamingElement
How to list all nodes in a tree (C#)
9/3/2020 • 4 minutes to read • Edit Online
Sometimes it is helpful to list all nodes in a tree. This can be useful when learning exactly how a method or property
affects the tree. One approach to listing all nodes in a textual form is to generate an XPath expression that exactly
and specifically identifies any node in the tree.
It is not particularly helpful to execute XPath expressions using LINQ to XML. XPath expressions have poorer
performance than LINQ to XML queries, and LINQ to XML queries are much more powerful. However, as a way to
identify nodes in the XML tree, XPath works well.
Example
This example shows a function named GetXPath that generates a specific XPath expression for any node in the XML
tree. It generates appropriate XPath expressions even when nodes are in a namespace. The XPath expressions are
generated by using namespace prefixes.
The example then creates a small XML tree that contains an example of several types of nodes. It then iterates
through the descendant nodes and prints the XPath expression for each node.
You will notice that the XML declaration is not a node in the tree.
The following is an XML file that contains several types of nodes:
The following is the list of nodes in the above XML tree, expressed as XPath expressions:
/processing-instruction()
/Root
/Root/@AttName
/Root/@xmlns:aw
/Root/comment()
/Root/Child[1]
/Root/Child[1]/text()
/Root/Child[2]
/Root/Child[2]/text()
/Root/ChildWithMixedContent
/Root/ChildWithMixedContent/text()[1]
/Root/ChildWithMixedContent/b
/Root/ChildWithMixedContent/b/text()
/Root/ChildWithMixedContent/text()[2]
/Root/aw:ElementInNamespace
/Root/aw:ElementInNamespace/aw:ChildInNamespace
class Program
{
static void Main(string[] args)
{
XNamespace aw = "http://www.adventure-works.com";
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XProcessingInstruction("target", "data"),
new XElement("Root",
new XAttribute("AttName", "An Attribute"),
new XAttribute(XNamespace.Xmlns + "aw", aw.ToString()),
new XComment("This is a comment"),
new XElement("Child",
new XText("Text")
),
new XElement("Child",
new XText("Other Text")
),
new XElement("ChildWithMixedContent",
new XText("text"),
new XElement("b", "BoldText"),
new XText("otherText")
),
new XElement(aw + "ElementInNamespace",
new XElement(aw + "ChildInNamespace")
)
)
);
doc.Save("Test.xml");
Console.WriteLine(File.ReadAllText("Test.xml"));
Console.WriteLine("------");
foreach (XObject obj in doc.DescendantNodes())
{
Console.WriteLine(obj.GetXPath());
XElement el = obj as XElement;
if (el != null)
foreach (XAttribute at in el.Attributes())
Console.WriteLine(at.GetXPath());
}
}
}
This topic presents an example that opens an Office Open XML document, and retrieves a collection of all of the
paragraphs in the document.
For more information on Office Open XML, see Open XML SDK and www.ericwhite.com.
Example
This example opens an Office Open XML package, uses the relationships within the Open XML package to find the
document and the style parts. It then queries the document, projecting a collection of an anonymous type that
contains the paragraph XElement node, the style name of each paragraph, and the text of each paragraph.
The example uses an extension method named StringConcatenate , which is also supplied in the example.
For a detailed tutorial that explains how this example works, see Pure Functional Transformations of XML (C#).
This example uses classes found in the WindowsBase assembly. It uses types in the System.IO.Packaging
namespace.
string defaultStyle =
(string)(
from style in styleDoc.Root.Elements(w + "style")
where (string)style.Attribute(w + "type") == "paragraph" &&
(string)style.Attribute(w + "default") == "1"
select style
).First().Attribute(w + "styleId");
// Find all paragraphs in the document.
var paragraphs =
from para in xDoc
.Root
.Element(w + "body")
.Descendants(w + "p")
let styleNode = para
.Elements(w + "pPr")
.Elements(w + "pStyle")
.FirstOrDefault()
select new
{
ParagraphNode = para,
StyleName = styleNode != null ?
(string)styleNode.Attribute(w + "val") :
defaultStyle
};
When run with the sample Open XML document described in Creating the Source Office Open XML Document (C#),
this example produces the following output:
This topic presents an example that opens an Office Open XML document, modifies it, and saves it.
For more information on Office Open XML, see Open XML SDK and www.ericwhite.com.
Example
This example finds the first paragraph element in the document. It retrieves the text from the paragraph, and then
deletes all text runs in the paragraph. It creates a new text run that consists of the first paragraph text that has been
converted to upper case. It then serializes the changed XML into the Open XML package and closes it.
This example uses classes found in the WindowsBase assembly. It uses types in the System.IO.Packaging
namespace.
class Program
{
public static string ParagraphText(XElement e)
{
XNamespace w = e.Name.Namespace;
return e
.Elements(w + "r")
.Elements(w + "t")
.StringConcatenate(element => (string)element);
}
if (styleRelation != null)
{
Uri styleUri = PackUriHelper.ResolvePartUri(documentUri, styleRelation.TargetUri);
stylePart = wdPackage.GetPart(styleUri);
paraNode.Add(
new XElement(w + "r",
new XElement(w + "t", paraText.ToUpper())
)
);
If you open SampleDoc.docx after running this program, you can see that this program converted the first
paragraph in the document to upper case.
When run with the sample Open XML document described in Creating the Source Office Open XML Document (C#),
this example produces the following output:
A common and useful application of XML trees is as a hierarchical name/value data store. You can populate an XML
tree with hierarchical data, and then query it, transform it, and if necessary, serialize it. In this usage scenario, many
of the XML specific semantics, such as namespaces and white space behavior, are not important. Instead, you are
using the XML tree as a small, in memory, single user hierarchical database.
Example
The following example populates an XML tree from the local file system using recursion. It then queries the tree,
calculating the total of the sizes of all files in the tree.
class Program
{
static XElement CreateFileSystemXmlTree(string source)
{
DirectoryInfo di = new DirectoryInfo(source);
return new XElement("Dir",
new XAttribute("Name", di.Name),
from d in Directory.GetDirectories(source)
select CreateFileSystemXmlTree(d),
from fi in di.GetFiles()
select new XElement("File",
new XElement("Name", fi.Name),
new XElement("Length", fi.Length)
)
);
}
XPath and LINQ to XML offer some similar functionality. Both can be used to query an XML tree, returning such
results as a collection of elements, a collection of attributes, a collection of nodes, or the value of an element or
attribute. However, there are also some differences.
Result Ordering
The XPath 1.0 Recommendation states that a collection that is the result of evaluating an XPath expression is
unordered.
However, when iterating through a collection returned by a LINQ to XML XPath axis method, the nodes in the
collection are returned in document order. This is the case even when accessing the XPath axes where predicates are
expressed in terms of reverse document order, such as preceding and preceding-sibling .
By contrast, most of the LINQ to XML axes return collections in document order, but two of them, Ancestors and
AncestorsAndSelf, return collections in reverse document order. The following table enumerates the axes, and
indicates collection order for each:
L IN Q TO XM L A XIS O RDERIN G
Positional Predicates
Within an XPath expression, positional predicates are expressed in terms of document order for many axes, but are
expressed in reverse document order for reverse axes, which are preceding , preceding-sibling , ancestor , and
ancestor-or-self . For example, the XPath expression preceding-sibling::*[1] returns the immediately preceding
sibling. This is the case even though the final result set is presented in document order.
By contrast, all positional predicates in LINQ to XML are always expressed in terms of the order of the axis. For
example, anElement.ElementsBeforeSelf().ElementAt(0) returns the first child element of the parent of the queried
element, not the immediate preceding sibling. Another example: anElement.Ancestors().ElementAt(0) returns the
parent element.
If you wanted to find the immediately preceding element in LINQ to XML, you would write the following expression:
ElementsBeforeSelf().Last()
ElementsBeforeSelf().Last()
Performance Differences
XPath queries that use the XPath functionality in LINQ to XML will not perform as well as LINQ to XML queries.
Comparison of Composition
Composition of a LINQ to XML query is somewhat parallel to composition of an XPath expression, although very
different in syntax.
For example, if you have an element in a variable named customers , and you want to find a grandchild element
named CompanyName under all child elements named Customer , you would write an XPath expression as follows:
customers.XPathSelectElements("./Customer/CompanyName")
customers.XPathSelectElements("./Customer/CompanyName")
customers.Elements("Customer").Elements("CompanyName")
customers.Elements("Customer").Elements("CompanyName")
or
XElement.Attributes
or
XContainer.DescendantNodes
descendant-or-self XElement.DescendantsAndSelf
or
XElement.DescendantNodesAndSelf
following-sibling XNode.ElementsAfterSelf
or
XNode.NodesAfterSelf
preceding-sibling XNode.ElementsBeforeSelf
or
XNode.NodesBeforeSelf
This topic compares the XPath child element axis to the LINQ to XML Element method.
The XPath expression is DeliveryNotes .
Example
This example finds the child element DeliveryNotes .
This example uses the following XML document: Sample XML File: Multiple Purchase Orders (LINQ to XML).
// XPath expression
XElement el2 = po.XPathSelectElement("DeliveryNotes");
// same as "child::DeliveryNotes"
// same as "./DeliveryNotes"
if (el1 == el2)
Console.WriteLine("Results are identical");
else
Console.WriteLine("Results differ");
Console.WriteLine(el1);
This topic compares the XPath child elements axis to the LINQ to XML Elements axis.
The XPath expression is: ./*
Example
This example finds all of the child elements of the Address element.
This example uses the following XML document: Sample XML File: Multiple Purchase Orders (LINQ to XML).
// XPath expression
IEnumerable<XElement> list2 = po.XPathSelectElements("./*");
This topic shows how to get the root element with XPath and LINQ to XML.
The XPath expression is:
/PurchaseOrders
Example
This example finds the root element.
This example uses the following XML document: Sample XML File: Multiple Purchase Orders (LINQ to XML).
XDocument po = XDocument.Load("PurchaseOrders.xml");
// XPath expression
XElement el2 = po.XPathSelectElement("/PurchaseOrders");
if (el1 == el2)
Console.WriteLine("Results are identical");
else
Console.WriteLine("Results differ");
Console.WriteLine(el1.Name);
This topic shows how to get the descendant elements with a particular name.
The XPath expression is //Name .
Example
This example finds all descendants named Name .
This example uses the following XML document: Sample XML File: Multiple Purchase Orders (LINQ to XML).
XDocument po = XDocument.Load("PurchaseOrders.xml");
// XPath expression
IEnumerable<XElement> list2 = po.XPathSelectElements("//Name");
This topic shows how to get the descendant elements with a specified name, and with an attribute with a specified
value.
The XPath expression is:
.//Address[@Type='Shipping']
Example
This example finds all descendants elements with the name of Address , and with a Type attribute with a value of
"Shipping".
This example uses the following XML document: Sample XML File: Multiple Purchase Orders (LINQ to XML).
XDocument po = XDocument.Load("PurchaseOrders.xml");
// XPath expression
IEnumerable<XElement> list2 = po.XPathSelectElements(".//Address[@Type='Shipping']");
This topic shows how to get an element selecting on an attribute that is referred to by the value of another element.
The XPath expression is:
.//Customer[@CustomerID=/Root/Orders/Order[12]/CustomerID]
Example
This example finds the 12th Order element, and then finds the customer for that order.
Note that indexing into a list in .NET is 'zero' based. Indexing into a collection of nodes in an XPath predicate is 'one'
based. This example reflects this difference.
This example uses the following XML document: Sample XML File: Customers and Orders (LINQ to XML).
XDocument co = XDocument.Load("CustomersOrders.xml");
// XPath expression
XElement customer3 = co.XPathSelectElement(
".//Customer[@CustomerID=/Root/Orders/Order[12]/CustomerID]");
XPath expressions can find nodes in a particular namespace. XPath expressions use namespace prefixes for
specifying namespaces. To parse an XPath expression that contains namespace prefixes, you must pass an object to
the XPath methods that implements IXmlNamespaceResolver. This example uses XmlNamespaceManager.
The XPath expression is:
./aw:*
Example
The following example reads an XML tree that contains two namespaces. It uses an XmlReader to read the XML
document. It then gets an XmlNameTable from the XmlReader, and an XmlNamespaceManager from the
XmlNameTable. It uses the XmlNamespaceManager when selecting elements.
This topic compares the XPath preceding-sibling axis to the LINQ to XML child XNode.ElementsBeforeSelf axis.
The XPath expression is:
preceding-sibling::*
Note that the results of both XPathSelectElements and XNode.ElementsBeforeSelf are in document order.
Example
The following example finds the FullAddress element, and then retrieves the previous elements using the
preceding-sibling axis.
This example uses the following XML document: Sample XML File: Customers and Orders (LINQ to XML).
XElement co = XElement.Load("CustomersOrders.xml");
// XPath expression
IEnumerable<XElement> list2 = add.XPathSelectElements("preceding-sibling::*");
This topic shows how to get the descendant elements of a child element with a particular name.
The XPath expression is:
./Paragraph//Text/text()
Example
This example simulates the problems of extracting text from an XML representation of a word processing
document. It first selects all Paragraph elements, and then it selects all Text descendant elements of each
Paragraph element. This doesn't select the descendant Text elements of the Comment element.
XElement root = XElement.Parse(
@"<Root>
<Paragraph>
<Text>This is the start of</Text>
</Paragraph>
<Comment>
<Text>This comment is not part of the paragraph text.</Text>
</Comment>
<Paragraph>
<Annotation Emphasis='true'>
<Text> a sentence.</Text>
</Annotation>
</Paragraph>
<Paragraph>
<Text> This is a second sentence.</Text>
</Paragraph>
</Root>");
// XPath expression
string str2 =
((IEnumerable)root.XPathEvaluate("./Paragraph//Text/text()"))
.Cast<XText>()
.Select(s => s.Value)
.Aggregate(
new StringBuilder(),
(s, i) => s.Append(i),
s => s.ToString()
);
if (str1 == str2)
Console.WriteLine("Results are identical");
else
Console.WriteLine("Results differ");
Console.WriteLine(str2);
XPath allows you to find the union of the results of two XPath location paths.
The XPath expression is:
//Category|//Price
You can achieve the same results by using the Concat standard query operator.
Example
This example finds all of the Category elements and all of the Price elements, and concatenates them into a single
collection. Note that the LINQ to XML query calls InDocumentOrder to order the results. The results of the XPath
expression evaluation are also in document order.
This example uses the following XML document: Sample XML File: Numerical Data (LINQ to XML).
// XPath expression
IEnumerable<XElement> list2 = data.XPathSelectElements("//Category|//Price");
You might want to find all siblings of a node that have a specific name. The resulting collection might include the
context node if the context node also has the specific name.
The XPath expression is:
../Book
Example
This example first finds a Book element, and then finds all sibling elements named Book . The resulting collection
includes the context node.
This example uses the following XML document: Sample XML File: Books (LINQ to XML).
XElement book =
books
.Root
.Elements("Book")
.Skip(1)
.First();
// XPath expression
IEnumerable<XElement> list2 = book.XPathSelectElements("../Book");
This topic shows how to navigate to the parent element and find an attribute of it.
The XPath expression is:
../@id
Example
This example first finds an Author element. It then finds the id attribute of the parent element.
This example uses the following XML document: Sample XML File: Books (LINQ to XML).
XElement author =
books
.Root
.Element("Book")
.Element("Author");
// XPath expression
XAttribute att2 = ((IEnumerable)author.XPathEvaluate("../@id")).Cast<XAttribute>().First();
if (att1 == att2)
Console.WriteLine("Results are identical");
else
Console.WriteLine("Results differ");
Console.WriteLine(att1);
This topic shows how to find all attributes of the siblings of the context node. Only attributes with a specific name
are returned in the collection.
The XPath expression is:
../Book/@id
Example
This example first finds a Book element, and then finds all sibling elements named Book , and then finds all
attributes named id . The result is a collection of attributes.
This example uses the following XML document: Sample XML File: Books (LINQ to XML).
XElement book =
books
.Root
.Element("Book");
// XPath expression
IEnumerable<XAttribute> list2 =
((IEnumerable)book.XPathEvaluate("../Book/@id")).Cast<XAttribute>();
Sometimes you want to find all elements that have a specific attribute. You are not concerned about the contents of
the attribute. Instead, you want to select based on the existence of the attribute.
The XPath expression is:
./*[@Select]
Example
The following code selects just the elements that have the Select attribute.
// XPath expression
IEnumerable<XElement> list2 =
((IEnumerable)doc.XPathEvaluate("./*[@Select]")).Cast<XElement>();
Sometimes you want to find elements based on their position. You might want to find the second element, or you
might want to find the third through the fifth element.
The XPath expression is:
Test[position() >= 2 and position() <= 4]
There are two approaches to writing this LINQ to XML query in a lazy way. You can use the Skip and Take operators,
or you can use the Where overload that takes an index. When you use the Where overload, you use a lambda
expression that takes two arguments. The following example shows both methods of selecting based on position.
Example
This example finds the second through the fourth Test element. The result is a collection of elements.
This example uses the following XML document: Sample XML File: Test Configuration (LINQ to XML).
// XPath expression
IEnumerable<XElement> list3 =
testCfg.XPathSelectElements("Test[position() >= 2 and position() <= 4]");
Sometimes you want to find the immediate preceding sibling to a node. Due to the difference in the semantics of
positional predicates for the preceding sibling axes in XPath as opposed to LINQ to XML, this is one of the more
interesting comparisons.
Example
In this example, the LINQ to XML query uses the Last operator to find the last node in the collection returned by
ElementsBeforeSelf. By contrast, the XPath expression uses a predicate with a value of 1 to find the immediately
preceding element.
// XPath expression
XElement el2 =
((IEnumerable)child4
.XPathEvaluate("preceding-sibling::*[1]"))
.Cast<XElement>()
.First();
if (el1 == el2)
Console.WriteLine("Results are identical");
else
Console.WriteLine("Results differ");
Console.WriteLine(el1);
This section introduces functional transformations, including the underlying concepts and supporting language
constructs. It contrasts the object-oriented and functional transformation approaches to programming, including
advice on how to transition to the latter. Although functional transformations can be used in many programming
scenarios, XML transformation is used here as a concrete example.
The Tutorial: Manipulating Content in a WordprocessingML Document (C#) tutorial provides a series of examples,
each building on the previous one. These examples demonstrate the pure functional transformational approach to
manipulating XML. This tutorial assumes a working knowledge of C#. Detailed semantics of the language
constructs are not provided in this tutorial, but links are provided to the language documentation as appropriate.
A working knowledge of basic computer science concepts and XML, including XML namespaces, is also assumed.
In This Section
TO P IC DESC RIP T IO N
Concepts and Terminology (Functional Transformation) (C#) Introduces the concepts and terminology of pure functional
transformations.
Functional Programming vs. Imperative Programming (C#) Compares and contrasts functional programming to more
traditional imperative (procedural) programming.
Refactoring Into Pure Functions (C#) Introduces pure functions, and shows examples of and pure
and impure functions.
Applicability of Functional Transformation (C#) Describes typical scenarios for functional transformations.
Functional Transformation of XML (Visual Basic) Describes functional transformations in the context of
transforming XML trees.
Concepts and Terminology (Functional
Transformation) (C#)
9/3/2020 • 3 minutes to read • Edit Online
This topic introduces the concepts and terminology of pure functional transformations. The functional
transformation approach to transforming data yields code that is often quicker to program, more expressive, and
easier to debug and maintain than more traditional, imperative programming.
Note that the topics in this section are not intended to fully explain functional programming. Instead, these topics
identify some of the functional programming capabilities that make it easier to transform XML from one shape to
another.
IMPORTANT
In the rest of this tutorial, the term "pure function" is used in a general sense to indicate a programming approach, and not a
specific language feature.
Note that pure functions must be implemented as methods in C#.
Also, you should not confuse pure functions with pure virtual methods in C++. The latter indicates that the containing class
is abstract and that no method body is supplied.
Functional Programming
Functional programming is a programming approach that directly supports pure functional transformation.
Historically, general-purpose functional programming languages, such as ML, Scheme, Haskell, and F#, have been
primarily of interest to the academic community. Although it has always been possible to write pure functional
transformations in C#, the difficulty of doing so has not made it an attractive option to most programmers. In
recent versions of C#, however, new language constructs such as lambda expressions and type inference make it
functional programming much easier and more productive.
For more information about functional programming, see Functional Programming vs. Imperative Programming
(C#).
Domain-Specific FP Languages
Although general functional programming languages have not been widely adopted, specific domain-specific
functional programming languages have had better success. For example, Cascading Style Sheets (CSS) are used to
determine the look and feel of many Web pages, and Extensible Stylesheet Language Transformations (XSLT) style
sheets are used extensively in XML data manipulation. For more information about XSLT, see XSLT Transformations.
Terminology
The following table defines some terms related to functional transformations.
higher-order (first-class) function
A function that can be treated as a programmatic object. For example, a higher-order function can be passed to or
returned from other functions. In C#c, delegates and lambda expressions are language features that support
higher-order functions. To write a higher-order function, you declare one or more arguments to take delegates, and
you often use lambda expressions when calling it. Many of the standard query operators are higher-order
functions.
For more information, see Standard Query Operators Overview (C#).
lambda expression
Essentially, an inline anonymous function that can be used wherever a delegate type is expected. This is a simplified
definition of lambda expressions, but it is adequate for the purposes of this tutorial.
For more information about, see Lambda Expressions.
collection
A structured set of data, usually of a uniform type. To be compatible with LINQ, a collection must implement the
IEnumerable interface or the IQueryable interface (or one of their generic counterparts, IEnumerator<T> or
IQueryable<T>).
tuple (anonymous types)
A mathematical concept, a tuple is a finite sequence of objects, each of a specific type. A tuple is also known as an
ordered list. Anonymous types are a language implementation of this concept, which enable an unnamed class type
to be declared and an object of that type to be instantiated at the same time.
For more information, see Anonymous Types.
type inference (implicit typing)
The ability of a compiler to determine the type of a variable in the absence of an explicit type declaration.
For more information, see Implicitly Typed Local Variables.
deferred execution and lazy evaluation
The delaying of evaluation of an expression until its resolved value is actually required. Deferred execution is
supported in collections.
For more information, see Introduction to LINQ Queries (C#) and Deferred Execution and Lazy Evaluation in LINQ
to XML (C#).
These language features will be used in code samples throughout this section.
See also
Introduction to Pure Functional Transformations (C#)
Functional Programming vs. Imperative Programming (C#)
Functional Programming vs. Imperative
Programming (C#)
9/3/2020 • 3 minutes to read • Edit Online
This topic compares and contrasts functional programming with more traditional imperative (procedural)
programming.
Programmer focus How to perform tasks (algorithms) and What information is desired and what
how to track changes in state. transformations are required.
Primary flow control Loops, conditionals, and function Function calls, including recursion.
(method) calls.
Primary manipulation unit Instances of structures or classes. Functions as first-class objects and data
collections.
Although most languages were designed to support a specific programming paradigm, many general languages
are flexible enough to support multiple paradigms. For example, most languages that contain function pointers
can be used to credibly support functional programming. Furthermore, C# includes explicit language extensions to
support functional programming, including lambda expressions and type inference. LINQ technology is a form of
declarative, functional programming.
See also
Introduction to Pure Functional Transformations (C#)
XSLT Transformations
Refactoring Into Pure Functions (C#)
Refactoring Into Pure Functions (C#)
9/3/2020 • 3 minutes to read • Edit Online
An important aspect of pure functional transformations is learning how to refactor code using pure functions.
NOTE
The common nomenclature in functional programming is that you refactor programs using pure functions. In Visual Basic
and C++, this aligns with the use of functions in the respective languages. However, in C#, functions are called methods. For
the purposes of this discussion, a pure function is implemented as a method in C#.
As noted previously in this section, a pure function has two useful characteristics:
It has no side effects. The function does not change any variables or the data of any type outside of the
function.
It is consistent. Given the same set of input data, it will always return the same output value.
One way of transitioning to functional programming is to refactor existing code to eliminate unnecessary side
effects and external dependencies. In this way, you can create pure function versions of existing code.
This topic discusses what a pure function is and what it is not. The Tutorial: Manipulating Content in a
WordprocessingML Document (C#) tutorial shows how to manipulate a WordprocessingML document, and
includes two examples of how to refactor using a pure function.
StringOne-StringTwo
Note that it is irrelevant whether the data being modified has public or private access, or is a static member
or an instance member. A pure function does not change any data outside of the function.
Non-Pure Function that Changes an Argument
Furthermore, the following version of this same function is not pure because it modifies the contents of its
parameter, sb .
This version of the program produces the same output as the first version, because the HyphenatedConcat function
has changed the value (state) of its first parameter by invoking the Append member function. Note that this
alteration occurs despite that fact that HyphenatedConcat uses call-by-value parameter passing.
IMPORTANT
For reference types, if you pass a parameter by value, it results in a copy of the reference to an object being passed. This
copy is still associated with the same instance data as the original reference (until the reference variable is assigned to a new
object). Call-by-reference is not necessarily required for a function to modify a parameter.
Pure Function
This next version of the program shows how to implement the HyphenatedConcat function as a pure function.
class Program
{
public static string HyphenatedConcat(string s, string appendStr)
{
return (s + '-' + appendStr);
}
Again, this version produces the same line of output: StringOne-StringTwo . Note that to retain the concatenated
value, it is stored in the intermediate variable s2 .
One approach that can be very useful is to write functions that are locally impure (that is, they declare and modify
local variables) but are globally pure. Such functions have many of the desirable composability characteristics, but
avoid some of the more convoluted functional programming idioms, such as having to use recursion when a
simple loop would accomplish the same thing.
Standard Query Operators
An important characteristic of the standard query operators is that they are implemented as pure functions.
For more information, see Standard Query Operators Overview (C#).
See also
Introduction to Pure Functional Transformations (C#)
Functional Programming vs. Imperative Programming (C#)
Applicability of Functional Transformation (C#)
9/3/2020 • 2 minutes to read • Edit Online
See also
Introduction to Pure Functional Transformations (C#)
Functional Transformation of XML (C#)
Refactoring Into Pure Functions (C#)
Functional Transformation of XML (C#)
9/3/2020 • 2 minutes to read • Edit Online
This topic discusses the pure functional transformation approach to modifying XML documents, and contrasts it
with a procedural approach.
See also
Introduction to Pure Functional Transformations (C#)
Tutorial: Manipulating Content in a WordprocessingML Document (C#)
LINQ to XML vs. Other XML Technologies
Deferred Execution and Lazy Evaluation in LINQ to
XML (C#)
9/3/2020 • 2 minutes to read • Edit Online
Query and axis operations are often implemented to use deferred execution. This topic explains the requirements
and advantages of deferred execution, and some implementation considerations.
Deferred Execution
Deferred execution means that the evaluation of an expression is delayed until its realized value is actually
required. Deferred execution can greatly improve performance when you have to manipulate large data
collections, especially in programs that contain a series of chained queries or manipulations. In the best case,
deferred execution enables only a single iteration through the source collection.
The LINQ technologies make extensive use of deferred execution in both the members of core System.Linq
classes and in the extension methods in the various LINQ namespaces, such as System.Xml.Linq.Extensions.
Deferred execution is supported directly in the C# language by the yield keyword (in the form of the
yield-return statement) when used within an iterator block. Such an iterator must return a collection of type
IEnumerator or IEnumerator<T> (or a derived type).
Next Steps
The next topic in this tutorial illustrates deferred execution:
Deferred Execution Example (C#)
See also
Tutorial: Chaining Queries Together (C#)
Concepts and Terminology (Functional Transformation) (C#)
Aggregation Operations (C#)
yield
Deferred Execution Example (C#)
9/3/2020 • 2 minutes to read • Edit Online
This topic shows how deferred execution and lazy evaluation affect the execution of your LINQ to XML queries.
Example
The following example shows the order of execution when using an extension method that uses deferred execution.
The example declares an array of three strings. It then iterates through the collection returned by
ConvertCollectionToUpperCase .
class Program
{
static void Main(string[] args)
{
string[] stringArray = { "abc", "def", "ghi" };
Notice that when iterating through the collection returned by ConvertCollectionToUpperCase , each item is retrieved
from the source string array and converted to uppercase before the next item is retrieved from the source string
array.
You can see that the entire array of strings is not converted to uppercase before each item in the returned
collection is processed in the foreach loop in Main .
The next topic in this tutorial illustrates chaining queries together:
Chaining Queries Example (C#)
See also
Tutorial: Chaining Queries Together (C#)
Chaining Queries Example (C#)
9/3/2020 • 2 minutes to read • Edit Online
This example builds on the previous example and shows what happens when you chain together two queries that
both use deferred execution and lazy evaluation.
Example
In this example, another extension method is introduced, AppendString , which appends a specified string onto
every string in the source collection, and then yields the new strings.
class Program
{
static void Main(string[] args)
{
string[] stringArray = { "abc", "def", "ghi" };
IEnumerable<string> q1 =
from s in stringArray.ConvertCollectionToUpperCase()
select s;
IEnumerable<string> q2 =
from s in q1.AppendString("!!!")
select s;
In this example, you can see that each extension method operates one at a time for each item in the source
collection.
What should be clear from this example is that even though we have chained together queries that yield collections,
no intermediate collections are materialized. Instead, each item is passed from one lazy method to the next. This
results in a much smaller memory footprint than an approach that would first take one array of strings, then create
a second array of strings that have been converted to uppercase, and finally create a third array of strings where
each string has the exclamation points appended to it.
The next topic in this tutorial illustrates intermediate materialization:
Intermediate Materialization (C#)
See also
Tutorial: Chaining Queries Together (C#)
Intermediate Materialization (C#)
9/3/2020 • 2 minutes to read • Edit Online
If you are not careful, in some situations you can drastically alter the memory and performance profile of your
application by causing premature materialization of collections in your queries. Some standard query operators
cause materialization of their source collection before yielding a single element. For example, Enumerable.OrderBy
first iterates through its entire source collection, then sorts all items, and then finally yields the first item. This
means that it is expensive to get the first item of an ordered collection; each item thereafter is not expensive. This
makes sense: It would be impossible for that query operator to do otherwise.
Example
This example alters the previous example. The AppendString method calls ToList before iterating through the
source. This causes materialization.
public static class LocalExtensions
{
public static IEnumerable<string>
ConvertCollectionToUpperCase(this IEnumerable<string> source)
{
foreach (string str in source)
{
Console.WriteLine("ToUpper: source >{0}<", str);
yield return str.ToUpper();
}
}
class Program
{
static void Main(string[] args)
{
string[] stringArray = { "abc", "def", "ghi" };
IEnumerable<string> q1 =
from s in stringArray.ConvertCollectionToUpperCase()
select s;
IEnumerable<string> q2 =
from s in q1.AppendString("!!!")
select s;
In this example, you can see that the call to ToList causes AppendString to enumerate its entire source before
yielding the first item. If the source were a large array, this would significantly alter the memory profile of the
application.
Standard query operators can also be chained together. The final topic in this tutorial illustrates this.
Chaining Standard Query Operators Together (C#)
See also
Tutorial: Chaining Queries Together (C#)
Chaining Standard Query Operators Together (C#)
9/3/2020 • 2 minutes to read • Edit Online
This is the final topic in the Tutorial: Chaining Queries Together (C#) tutorial.
The standard query operators can also be chained together. For example, you can interject the Enumerable.Where
operator, and it also operates in a lazy fashion. No intermediate results are materialized by it.
Example
In this example, the Where method is called before calling ConvertCollectionToUpperCase . The Where method
operates in almost exactly the same way as the lazy methods used in previous examples in this tutorial,
ConvertCollectionToUpperCase and AppendString .
One difference is that in this case, the Where method iterates through its source collection, determines that the first
item does not pass the predicate, and then gets the next item, which does pass. It then yields the second item.
However, the basic idea is the same: Intermediate collections are not materialized unless they have to be.
When query expressions are used, they are converted to calls to the standard query operators, and the same
principles apply.
All of the examples in this section that are querying Office Open XML documents use the same principle. Deferred
execution and lazy evaluation are some of the fundamental concepts that you must understand to use LINQ (and
LINQ to XML) effectively.
public static class LocalExtensions
{
public static IEnumerable<string>
ConvertCollectionToUpperCase(this IEnumerable<string> source)
{
foreach (string str in source)
{
Console.WriteLine("ToUpper: source >{0}<", str);
yield return str.ToUpper();
}
}
class Program
{
static void Main(string[] args)
{
string[] stringArray = { "abc", "def", "ghi" };
IEnumerable<string> q1 =
from s in stringArray.ConvertCollectionToUpperCase()
where s.CompareTo("D") >= 0
select s;
IEnumerable<string> q2 =
from s in q1.AppendString("!!!")
select s;
This document contains two paragraphs. They both contain a single text run, and each text run contains a single
text piece.
The easiest way to see the contents of a WordprocessingML document in XML form is to create one using
Microsoft Word, save it, and then run the following program that prints the XML to the console.
This example uses classes found in the WindowsBase assembly. It uses types in the System.IO.Packaging
namespace.
External resources
Introducing the Office (2007) Open XML File Formats
Overview of WordprocessingML
Anatomy of a WordProcessingML File
Introduction to WordprocessingML
See also
Tutorial: Manipulating Content in a WordprocessingML Document (C#)
Creating the Source Office Open XML Document
(C#)
9/3/2020 • 2 minutes to read • Edit Online
This topic shows how to create the Office Open XML WordprocessingML document that the other examples in this
tutorial use. If you follow these instructions, your output will match the output provided in each example.
However, the examples in this tutorial will work with any valid WordprocessingML document.
To create the document that this tutorial uses, you must either have Microsoft Office 2007 or later installed, or you
must have Microsoft Office 2003 with the Microsoft Office Compatibility Pack for Word, Excel, and PowerPoint
2007 File Formats.
using System;
class Program {
public static void Main(string[] args) {
Console.WriteLine("Hello World");
}
}
Hello World
NOTE
If you are using Microsoft Word 2003, select Word 2007 Document in the Save as Type drop-down list.
Finding the Default Paragraph Style (C#)
9/3/2020 • 2 minutes to read • Edit Online
The first task in the Manipulating Information in a WordprocessingML Document tutorial is to find the default style
of paragraphs in the document.
Example
Description
The following example opens an Office Open XML WordprocessingML document, finds the document and style
parts of the package, and then executes a query that finds the default style name. For information about Office
Open XML document packages, and the parts they consist of, see Details of Office Open XML WordprocessingML
Documents (C#).
The query finds a node named w:style that has an attribute named w:type with a value of "paragraph", and also
has an attribute named w:default with a value of "1". Because there will be only one XML node with these
attributes, the query uses the Enumerable.First operator to convert a collection to a singleton. It then gets the value
of the attribute with the name w:styleId .
This example uses classes from the WindowsBase assembly. It uses types in the System.IO.Packaging namespace.
Code
const string fileName = "SampleDoc.docx";
// The following query finds all the paragraphs that have the default style.
string defaultStyle =
(string)(
from style in styleDoc.Root.Elements(w + "style")
where (string)style.Attribute(w + "type") == "paragraph"&&
(string)style.Attribute(w + "default") == "1"
select style
).First().Attribute(w + "styleId");
Comments
This example produces the following output:
Next Steps
In the next example, you'll create a similar query that finds all the paragraphs in a document and their styles:
Retrieving the Paragraphs and Their Styles (C#)
Retrieving the Paragraphs and Their Styles (C#)
9/3/2020 • 3 minutes to read • Edit Online
In this example, we write a query that retrieves the paragraph nodes from a WordprocessingML document. It also
identifies the style of each paragraph.
This query builds on the query in the previous example, Finding the Default Paragraph Style (C#), which retrieves
the default style from the list of styles. This information is required so that the query can identify the style of
paragraphs that do not have a style explicitly set. Paragraph styles are set through the w:pPr element; if a
paragraph does not contain this element, it is formatted with the default style.
This topic explains the significance of some pieces of the query, then shows the query as part of a complete,
working example.
Example
The source of the query to retrieve all the paragraphs in a document and their styles is as follows:
This expression is similar to the source of the query in the previous example, Finding the Default Paragraph Style
(C#). The main difference is that it uses the Descendants axis instead of the Elements axis. The query uses the
Descendants axis because in documents that have sections, the paragraphs will not be the direct children of the
body element; rather, the paragraphs will be two levels down in the hierarchy. By using the Descendants axis, the
code will work of whether or not the document uses sections.
Example
The query uses a let clause to determine the element that contains the style node. If there is no element, then
styleNode is set to null :
The let clause first uses the Elements axis to find all elements named pPr , then uses the Elements extension
method to find all child elements named pStyle , and finally uses the FirstOrDefault standard query operator to
convert the collection to a singleton. If the collection is empty, styleNode is set to null . This is a useful idiom to
look for the pStyle descendant node. Note that if the pPr child node does not exist, the code does nor fail by
throwing an exception; instead, styleNode is set to null , which is the desired behavior of this let clause.
The query projects a collection of an anonymous type with two members, StyleName and ParagraphNode .
Example
This example processes a WordprocessingML document, retrieving the paragraph nodes from a
WordprocessingML document. It also identifies the style of each paragraph. This example builds on the previous
examples in this tutorial. The new query is called out in comments in the code below.
You can find instructions for creating the source document for this example in Creating the Source Office Open
XML Document (C#).
This example uses classes found in the WindowsBase assembly. It uses types in the System.IO.Packaging
namespace.
string defaultStyle =
(string)(
from style in styleDoc.Root.Elements(w + "style")
where (string)style.Attribute(w + "type") == "paragraph"&&
(string)style.Attribute(w + "default") == "1"
select style
).First().Attribute(w + "styleId");
This example produces the following output when applied to the document described in Creating the Source Office
Open XML Document (C#).
StyleName:Heading1
StyleName:Normal
StyleName:Normal
StyleName:Normal
StyleName:Code
StyleName:Code
StyleName:Code
StyleName:Code
StyleName:Code
StyleName:Code
StyleName:Code
StyleName:Normal
StyleName:Normal
StyleName:Normal
StyleName:Code
Next Steps
In the next topic, Retrieving the Text of the Paragraphs (C#), you'll create a query to retrieve the text of paragraphs.
See also
Tutorial: Manipulating Content in a WordprocessingML Document (C#)
Retrieving the Text of the Paragraphs (C#)
9/3/2020 • 3 minutes to read • Edit Online
This example builds on the previous example, Retrieving the Paragraphs and Their Styles (C#). This new example
retrieves the text of each paragraph as a string.
To retrieve the text, this example adds an additional query that iterates through the collection of anonymous types
and projects a new collection of an anonymous type with the addition of a new member, Text . It uses the
Aggregate standard query operator to concatenate multiple strings into one string.
This technique (that is, first projecting to a collection of an anonymous type, then using this collection to project to
a new collection of an anonymous type) is a common and useful idiom. This query could have been written without
projecting to the first anonymous type. However, because of lazy evaluation, doing so does not use much additional
processing power. The idiom creates more short lived objects on the heap, but this does not substantially degrade
performance.
Of course, it would be possible to write a single query that contains the functionality to retrieve the paragraphs, the
style of each paragraph, and the text of each paragraph. However, it often is useful to break up a more complicated
query into multiple queries because the resulting code is more modular and easier to maintain. Furthermore, if you
need to reuse a portion of the query, it is easier to refactor if the queries are written in this manner.
These queries, which are chained together, use the processing model that is examined in detail in the topic Tutorial:
Chaining Queries Together (C#).
Example
This example processes a WordprocessingML document, determining the element node, the style name, and the
text of each paragraph. This example builds on the previous examples in this tutorial. The new query is called out in
comments in the code below.
For instructions for creating the source document for this example, see Creating the Source Office Open XML
Document (C#).
This example uses classes from the WindowsBase assembly. It uses types in the System.IO.Packaging namespace.
string defaultStyle =
(string)(
from style in styleDoc.Root.Elements(w + "style")
where (string)style.Attribute(w + "type") == "paragraph"&&
(string)style.Attribute(w + "default") == "1"
select style
).First().Attribute(w + "styleId");
This example produces the following output when applied to the document described in Creating the Source Office
Open XML Document (C#).
Next Steps
The next example shows how to use an extension method, instead of Aggregate, to concatenate multiple strings
into a single string.
Refactoring Using an Extension Method (C#)
See also
Tutorial: Manipulating Content in a WordprocessingML Document (C#)
Deferred Execution and Lazy Evaluation in LINQ to XML (C#)
Refactoring Using an Extension Method (C#)
9/3/2020 • 4 minutes to read • Edit Online
This example builds on the previous example, Retrieving the Text of the Paragraphs (C#), by refactoring the
concatenation of strings using a pure function that is implemented as an extension method.
The previous example used the Aggregate standard query operator to concatenate multiple strings into one string.
However, it is more convenient to write an extension method to do this, because the resulting query smaller and
more simple.
Example
This example processes a WordprocessingML document, retrieving the paragraphs, the style of each paragraph,
and the text of each paragraph. This example builds on the previous examples in this tutorial.
The example contains multiple overloads of the StringConcatenate method.
You can find instructions for creating the source document for this example in Creating the Source Office Open
XML Document (C#).
This example uses classes from the WindowsBase assembly. It uses types in the System.IO.Packaging namespace.
Console.WriteLine("{0}", numbers.StringConcatenate());
Console.WriteLine("{0}", numbers.StringConcatenate(":"));
int[] intNumbers = { 1, 2, 3 };
Console.WriteLine("{0}", intNumbers.StringConcatenate(i => i.ToString()));
Console.WriteLine("{0}", intNumbers.StringConcatenate(i => i.ToString(), ":"));
onetwothree
one:two:three:
123
1:2:3:
Example
Now, the example can be modified to take advantage of the new extension method:
class Program
{
static void Main(string[] args)
{
const string fileName = "SampleDoc.docx";
string defaultStyle =
(string)(
from style in styleDoc.Root.Elements(w + "style")
where (string)style.Attribute(w + "type") == "paragraph" &&
(string)style.Attribute(w + "default") == "1"
select style
).First().Attribute(w + "styleId");
This example produces the following output when applied to the document described in Creating the Source Office
Open XML Document (C#).
Note that this refactoring is a variant of refactoring into a pure function. The next topic will introduce the idea of
factoring into pure functions in more detail.
Next Steps
The next example shows how to refactor this code in another way, by using pure functions:
Refactoring Using a Pure Function (C#)
See also
Tutorial: Manipulating Content in a WordprocessingML Document (C#)
Refactoring Into Pure Functions (C#)
Refactoring Using a Pure Function (C#)
9/3/2020 • 3 minutes to read • Edit Online
The following example refactors the previous example, Refactoring Using an Extension Method (C#), to use a pure
function. In this example, the code to find the text of a paragraph is moved to the pure static method ParagraphText
.
Example
This example processes a WordprocessingML document, retrieving the paragraph nodes from a
WordprocessingML document. It also identifies the style of each paragraph. This example builds on the previous
examples in this tutorial. The refactored code is called out in comments in the code below.
For instructions for creating the source document for this example, see Creating the Source Office Open XML
Document (C#).
This example uses classes from the WindowsBase assembly. It uses types in the System.IO.Packaging namespace.
class Program
{
// This is a new method that assembles the paragraph text.
public static string ParagraphText(XElement e)
{
{
XNamespace w = e.Name.Namespace;
return e
.Elements(w + "r")
.Elements(w + "t")
.StringConcatenate(element => (string)element);
}
string defaultStyle =
(string)(
from style in styleDoc.Root.Elements(w + "style")
where (string)style.Attribute(w + "type") == "paragraph" &&
(string)style.Attribute(w + "default") == "1"
select style
).First().Attribute(w + "styleId");
Next Steps
The next example shows how to project XML into a different shape:
Projecting XML in a Different Shape (C#)
See also
Tutorial: Manipulating Content in a WordprocessingML Document (C#)
Refactoring Using an Extension Method (C#)
Refactoring Into Pure Functions (C#)
Projecting XML in a Different Shape (C#)
9/3/2020 • 3 minutes to read • Edit Online
This topic shows an example of projecting XML that is in a different shape than the source XML.
Many typical XML transformations consist of chained queries, as in this example. It is common to start with some
form of XML, project intermediate results as collections of anonymous types or named types, and then finally to
project the results back into XML that is in an entirely different shape than the source XML.
Example
This example processes a WordprocessingML document, retrieving the paragraph nodes from a
WordprocessingML document. It also identifies the style and text of each paragraph. Finally, the example projects
XML with a different shape. This example builds on the previous examples in this tutorial. The new statement that
does the projection is called out in comments in the code below.
For instructions for creating the source document for this example, see Creating the Source Office Open XML
Document (C#).
This example uses classes from the WindowsBase assembly. It uses types in the System.IO.Packaging namespace.
class Program
{
public static string ParagraphText(XElement e)
{
XNamespace w = e.Name.Namespace;
return e
.Elements(w + "r")
.Elements(w + "t")
.StringConcatenate(element => (string)element);
}
string defaultStyle =
(string)(
from style in styleDoc.Root.Elements(w + "style")
where (string)style.Attribute(w + "type") == "paragraph" &&
(string)style.Attribute(w + "default") == "1"
select style
).First().Attribute(w + "styleId");
// The following is the new code that projects XML in a new shape.
XElement root = new XElement("Root",
from p in paraWithText
select new XElement("Paragraph",
new XElement("StyleName", p.StyleName),
new XElement("Text", p.Text)
)
);
Console.WriteLine(root);
}
}
Next Steps
In the next example, you'll query to find all the text in a Word document:
Finding Text in Word Documents (C#)
Finding Text in Word Documents (C#)
9/3/2020 • 5 minutes to read • Edit Online
This topic extends the previous queries to do something useful: find all occurrences of a string in the document.
Example
This example processes a WordprocessingML document, to find all the occurrences of a specific piece of text in the
document. To do this, we use a query that finds the string "Hello". This example builds on the previous examples in
this tutorial. The new query is called out in comments in the code below.
For instructions for creating the source document for this example, see Creating the Source Office Open XML
Document (C#).
This example uses classes found in the WindowsBase assembly. It uses types in the System.IO.Packaging
namespace.
class Program
{
public static string ParagraphText(XElement e)
{
XNamespace w = e.Name.Namespace;
return e
return e
.Elements(w + "r")
.Elements(w + "t")
.StringConcatenate(element => (string)element);
}
string defaultStyle =
(string)(
from style in styleDoc.Root.Elements(w + "style")
where (string)style.Attribute(w + "type") == "paragraph" &&
(string)style.Attribute(w + "default") == "1"
select style
).First().Attribute(w + "styleId");
You can, of course, modify the search so that it searches for lines with a specific style. The following query finds all
blank lines that have the Code style:
class Program
{
public static string ParagraphText(XElement e)
{
XNamespace w = e.Name.Namespace;
return e
.Elements(w + "r")
.Elements(w + "t")
.StringConcatenate(element => (string)element);
}
string defaultStyle =
(string)(
from style in styleDoc.Root.Elements(w + "style")
where (string)style.Attribute(w + "type") == "paragraph" &&
(string)style.Attribute(w + "default") == "1"
(string)style.Attribute(w + "default") == "1"
select style
).First().Attribute(w + "styleId");
// Retrieve all paragraphs that have no text and are styled Code.
var blankCodeParagraphs =
from para in paraWithText
where para.Text == "" && para.StyleName == "Code"
select new
{
ParagraphNode = para.ParagraphNode,
StyleName = para.StyleName,
Text = para.Text
};
StyleName:Code ><
Of course, this example could be enhanced in a number of ways. For example, we could use regular expressions to
search for text, we could iterate through all the Word files in a particular directory, and so on.
Note that this example performs approximately as well as if it were written as a single query. Because each query is
implemented in a lazy, deferred fashion, each query does not yield its results until the query is iterated. For more
information about execution and lazy evaluation, see Deferred Execution and Lazy Evaluation in LINQ to XML (C#).
Next Steps
The next section provides more information about WordprocessingML documents:
Details of Office Open XML WordprocessingML Documents (C#)
See also
Tutorial: Manipulating Content in a WordprocessingML Document (C#)
Refactoring Using a Pure Function (C#)
Deferred Execution and Lazy Evaluation in LINQ to XML (C#)
WordprocessingML Document with Styles
9/3/2020 • 2 minutes to read • Edit Online
More complicated WordprocessingML documents have paragraphs that are formatted with styles.
A few notes about the makeup of WordprocessingML documents are helpful. WordprocessingML documents are
stored in packages. Packages have multiple parts (parts have an explicit meaning when used in the context of
packages; essentially, parts are files that are zipped together to comprise a package). If a document contains
paragraphs that are formatted with styles, there will be a document part that contains paragraphs that have styles
applied to them. There will also be a style part that contains the styles that are referred to by the document.
When accessing packages, it is important that you do so through the relationships between parts, rather than using
an arbitrary path. This issue is beyond the scope of the Manipulating Content in a WordprocessingML Document
tutorial, but the example programs that are included in this tutorial demonstrate the correct approach.
This topic shows an example of the style part of the Office Open XML WordprocessingML document.
Example
The following example is the XML that makes up the style part of an Office Open XML WordprocessingML
document.
The default paragraph style has an element with the following opening tag:
You need to know this information when you write the query to find the default style identifier, so that the query
can identify the style of paragraphs that have the default style.
Note that these documents are very simple when compared to typical documents that Microsoft Word generates. In
many cases, Word saves a great deal of additional information, additional formatting and metadata. Furthermore,
Word does not format the lines to be easily readable as in this example; instead, the XML is saved without
indentation. However, all WordprocessingML documents share the same basic XML shape. Because of this, the
queries presented in this tutorial will work with more complicated documents.
This topic shows how to open an Office Open XML document and access parts within it.
Example
The following example opens an Office Open XML document, and prints the document part and the style part to
the console.
This example uses classes from the WindowsBase assembly. It uses types in the System.IO.Packaging namespace.
const string fileName = "SampleDoc.docx";
Console.WriteLine("TargetUri:{0}", docPackageRelationship.TargetUri);
Console.WriteLine("==================================================================");
Console.WriteLine(xdoc.Root);
Console.WriteLine();
Console.WriteLine("TargetUri:{0}", styleRelation.TargetUri);
Console.WriteLine("==================================================================");
Console.WriteLine(styleDoc.Root);
Console.WriteLine();
}
}
}
In-Memory XML Tree Modification vs. Functional
Construction (LINQ to XML) (C#)
9/3/2020 • 3 minutes to read • Edit Online
Modifying an XML tree in place is a traditional approach to changing the shape of an XML document. A typical
application loads a document into a data store such as DOM or LINQ to XML; uses a programming interface to
insert nodes, delete nodes, or change the content of nodes; and then saves the XML to a file or transmits it over a
network.
LINQ to XML enables another approach that is useful in many scenarios: functional construction. Functional
construction treats modifying data as a problem of transformation, rather than as detailed manipulation of a data
store. If you can take a representation of data and transform it efficiently from one form to another, the result is the
same as if you took one data store and manipulated it in some way to take another shape. A key to the functional
construction approach is to pass the results of queries to XDocument and XElement constructors.
In many cases you can write the transformational code in a fraction of the time that it would take to manipulate the
data store, and that code is more robust and easier to maintain. In these cases, even though the transformational
approach can take more processing power, it is a more effective way to modify data. If a developer is familiar with
the functional approach, the resulting code in many cases is easier to understand. It is easy to find the code that
modifies each part of the tree.
The approach where you modify an XML tree in-place is more familiar to many DOM programmers, whereas code
written using the functional approach might look unfamiliar to a developer who doesn't yet understand that
approach. If you have to only make a small modification to a large XML tree, the approach where you modify a tree
in place in many cases will take less CPU time.
This topic provides an example that is implemented with both approaches.
<Root>
<Child1>Content</Child1>
<Data1>123</Data1>
<Data2>456</Data2>
</Root>
This example outputs the same XML as the first example. However, notice that you can actually see the resulting
structure of the new XML in the functional approach. You can see the creation of the Root element, the code that
pulls the Child1 element from the source tree, and the code that transforms the attributes from the source tree to
elements in the new tree.
The functional example in this case is not any shorter than the first example, and it is not really any simpler.
However, if you have many changes to make to an XML tree, the non functional approach will become quite
complex and somewhat obtuse. In contrast, when using the functional approach, you still just form the desired
XML, embedding queries and expressions as appropriate, to pull in the desired content. The functional approach
yields code that is easier to maintain.
Notice that in this case the functional approach probably would not perform quite as well as the tree manipulation
approach. The main issue is that the functional approach creates more short lived objects. However, the tradeoff is
an effective one if using the functional approach allows for greater programmer productivity.
This is a very simple example, but it serves to show the difference in philosophy between the two approaches. The
functional approach yields greater productivity gains for transforming larger XML documents.
Adding Elements, Attributes, and Nodes to an XML
Tree (C#)
9/3/2020 • 2 minutes to read • Edit Online
You can add content (elements, attributes, comments, processing instructions, text, and CDATA) to an existing XML
tree.
M ET H O D DESC RIP T IO N
The following methods add content as sibling nodes of an XNode. The most common node to which you add sibling
content is XElement, although you can add valid sibling content to other types of nodes such as XText or XComment.
M ET H O D DESC RIP T IO N
Example
Description
The following example creates two XML trees, and then modifies one of the trees.
Code
XElement srcTree = new XElement("Root",
new XElement("Element1", 1),
new XElement("Element2", 2),
new XElement("Element3", 3),
new XElement("Element4", 4),
new XElement("Element5", 5)
);
XElement xmlTree = new XElement("Root",
new XElement("Child1", 1),
new XElement("Child2", 2),
new XElement("Child3", 3),
new XElement("Child4", 4),
new XElement("Child5", 5)
);
xmlTree.Add(new XElement("NewChild", "new content"));
xmlTree.Add(
from el in srcTree.Elements()
where (int)el > 3
select el
);
// Even though Child9 does not exist in srcTree, the following statement will not
// throw an exception, and nothing will be added to xmlTree.
xmlTree.Add(srcTree.Element("Child9"));
Console.WriteLine(xmlTree);
Comments
This code produces the following output:
<Root>
<Child1>1</Child1>
<Child2>2</Child2>
<Child3>3</Child3>
<Child4>4</Child4>
<Child5>5</Child5>
<NewChild>new content</NewChild>
<Element4>4</Element4>
<Element5>5</Element5>
</Root>
Modifying Elements, Attributes, and Nodes in an XML
Tree
9/3/2020 • 2 minutes to read • Edit Online
The following table summarizes the methods and properties that you can use to modify an element, its child
elements, or its attributes.
The following methods modify an XElement.
M ET H O D DESC RIP T IO N
M ET H O D DESC RIP T IO N
M ET H O D DESC RIP T IO N
You can modify an XML tree, removing elements, attributes, and other types of nodes.
Removing a single element or a single attribute from an XML document is straightforward. However, when
removing collections of elements or attributes, you should first materialize a collection into a list, and then delete
the elements or attributes from the list. The best approach is to use the Remove extension method, which will do
this for you.
The main reason for doing this is that most of the collections you retrieve from an XML tree are yielded using
deferred execution. If you do not first materialize them into a list, or if you do not use the extension methods, it is
possible to encounter a certain class of bugs. For more information, see Mixed Declarative Code/Imperative Code
Bugs (LINQ to XML) (C#).
The following methods remove nodes and attributes from an XML tree.
M ET H O D DESC RIP T IO N
XElement.SetAttributeValue If you pass null for value, then removes the attribute.
XElement.SetElementValue If you pass null for value, then removes the child element.
Example
Description
This example demonstrates three approaches to removing elements. First, it removes a single element. Second, it
retrieves a collection of elements, materializes them using the Enumerable.ToList operator, and removes the
collection. Finally, it retrieves a collection of elements and removes them using the Remove extension method.
For more information on the ToList operator, see Converting Data Types (C#).
Code
XElement root = XElement.Parse(@"<Root>
<Child1>
<GrandChild1/>
<GrandChild2/>
<GrandChild3/>
</Child1>
<Child2>
<GrandChild4/>
<GrandChild5/>
<GrandChild6/>
</Child2>
<Child3>
<GrandChild7/>
<GrandChild8/>
<GrandChild9/>
</Child3>
</Root>");
root.Element("Child1").Element("GrandChild1").Remove();
root.Element("Child2").Elements().ToList().Remove();
root.Element("Child3").Elements().Remove();
Console.WriteLine(root);
Comments
This code produces the following output:
<Root>
<Child1>
<GrandChild2 />
<GrandChild3 />
</Child1>
<Child2 />
<Child3 />
</Root>
Notice that the first grandchild element has been removed from Child1 . All grandchildren elements have been
removed from Child2 and from Child3 .
Maintaining Name/Value Pairs (C#)
9/3/2020 • 2 minutes to read • Edit Online
Many applications have to maintain information that is best kept as name/value pairs. This information might be
configuration information or global settings. LINQ to XML contains some methods that make it easy to keep a set of
name/value pairs. You can either keep the information as attributes or as a set of child elements.
One difference between keeping the information as attributes or as child elements is that attributes have the
constraint that there can be only one attribute with a particular name for an element. This limitation does not apply
to child elements.
Example
The following example creates an element with no attributes. It then uses the SetAttributeValue method to create
and maintain a list of name/value pairs.
// Create an element with no content.
XElement root = new XElement("Root");
// Remove DefaultColor.
root.SetAttributeValue("DefaultColor", null);
Console.WriteLine(root);
Example
The following example creates an element with no child elements. It then uses the SetElementValue method to
create and maintain a list of name/value pairs.
// Remove DefaultColor.
root.SetElementValue("DefaultColor", null);
Console.WriteLine(root);
See also
SetAttributeValue
SetElementValue
Modifying XML Trees (LINQ to XML) (C#)
How to change the namespace for an entire XML tree
(C#)
9/3/2020 • 2 minutes to read • Edit Online
You sometimes have to programmatically change the namespace for an element or an attribute. LINQ to XML
makes this easy. The XElement.Name property can be set. The XAttribute.Name property cannot be set, but you can
easily copy the attributes into a System.Collections.Generic.List<T>, remove the existing attributes, and then add
new attributes that are in the new desired namespace.
For more information, see Namespaces Overview (LINQ to XML) (C#).
Example
The following code creates two XML trees in no namespace. It then changes the namespace of each of the trees, and
combines them into a single tree.
XElement tree1 = new XElement("Data",
new XElement("Child", "content",
new XAttribute("MyAttr", "content")
)
);
XElement tree2 = new XElement("Data",
new XElement("Child", "content",
new XAttribute("MyAttr", "content")
)
);
XNamespace aw = "http://www.adventure-works.com";
XNamespace ad = "http://www.adatum.com";
// change the namespace of every element and attribute in the first tree
foreach (XElement el in tree1.DescendantsAndSelf())
{
el.Name = aw.GetName(el.Name.LocalName);
List<XAttribute> atList = el.Attributes().ToList();
el.Attributes().Remove();
foreach (XAttribute at in atList)
el.Add(new XAttribute(aw.GetName(at.Name.LocalName), at.Value));
}
// change the namespace of every element and attribute in the second tree
foreach (XElement el in tree2.DescendantsAndSelf())
{
el.Name = ad.GetName(el.Name.LocalName);
List<XAttribute> atList = el.Attributes().ToList();
el.Attributes().Remove();
foreach (XAttribute at in atList)
el.Add(new XAttribute(ad.GetName(at.Name.LocalName), at.Value));
}
// add attribute namespaces so that the tree will be serialized with
// the aw and ad namespace prefixes
tree1.Add(
new XAttribute(XNamespace.Xmlns + "aw", "http://www.adventure-works.com")
);
tree2.Add(
new XAttribute(XNamespace.Xmlns + "ad", "http://www.adatum.com")
);
// create a new composite tree
XElement root = new XElement("Root",
tree1,
tree2
);
Console.WriteLine(root);
<Root>
<aw:Data xmlns:aw="http://www.adventure-works.com">
<aw:Child aw:MyAttr="content">content</aw:Child>
</aw:Data>
<ad:Data xmlns:ad="http://www.adatum.com">
<ad:Child ad:MyAttr="content">content</ad:Child>
</ad:Data>
</Root>
Performance of Chained Queries (LINQ to XML) (C#)
9/3/2020 • 2 minutes to read • Edit Online
One of the most important benefits of LINQ (and LINQ to XML) is that chained queries can perform as well as a
single larger, more complicated query.
A chained query is a query that uses another query as its source. For example, in the following simple code, query2
has query1 as its source:
This chained query provides the same performance profile as iterating through a linked list.
The Elements axis has essentially the same performance as iterating through a linked list. Elements is
implemented as an iterator with deferred execution. This means that it does some work in addition to
iterating through the linked list, such as allocating the iterator object and keeping track of execution state.
This work can be divided into two categories: the work that is done at the time the iterator is set up, and the
work that is done during each iteration. The setup work is a small, fixed amount of work and the work done
during each iteration is proportional to the number of items in the source collection.
In query1 , the where clause causes the query to call the Where method. This method is also implemented
as an iterator. The setup work consists of instantiating the delegate that will reference the lambda expression,
plus the normal setup for an iterator. With each iteration, the delegate is called to execute the predicate. The
setup work and the work done during each iteration is the similar to the work done while iterating through
the axis.
In query1 , the select clause causes the query to call the Select method. This method has the same
performance profile as the Where method.
In query2 , both the where clause and the select clause have the same performance profile as in query1 .
The iteration through query2 is therefore directly proportional to the number of items in the source of the first
query, in other words, linear time. A corresponding Visual Basic example would have the same performance profile.
For more information on iterators, see yield.
For a more detailed tutorial on chaining queries together, see Tutorial: Chaining Queries Together.
Atomized XName and XNamespace Objects (LINQ to
XML) (C#)
9/3/2020 • 2 minutes to read • Edit Online
XName and XNamespace objects are atomized; that is, if they contain the same qualified name, they refer to the
same object. This yields performance benefits for queries: When you compare two atomized names for equality, the
underlying intermediate language only has to determine whether the two references point to the same object. The
underlying code does not have to do string comparisons, which would be time consuming.
Atomization Semantics
Atomization means that if two XName objects have the same local name, and they are in the same namespace, they
share the same instance. In the same way, if two XNamespace objects have the same namespace URI, they share the
same instance.
For a class to enable atomized objects, the constructor for the class must be private, not public. This is because if the
constructor were public, you could create a non-atomized object. The XName and XNamespace classes implement
an implicit conversion operator to convert a string into an XName or XNamespace. This is how you get an instance
of these objects. You cannot get an instance by using a constructor, because the constructor is inaccessible.
XName and XNamespace also implement the equality and inequality operators, to determine whether the two
objects being compared are references to the same instance.
Example
The following code creates some XElement objects and demonstrates that identical names share the same instance.
if ((object)r1.Name == (object)r2.Name)
Console.WriteLine("r1 and r2 have names that refer to the same instance.");
else
Console.WriteLine("Different");
XName n = "Root";
if ((object)n == (object)r1.Name)
Console.WriteLine("The name of r1 and the name in 'n' refer to the same instance.");
else
Console.WriteLine("Different");
As mentioned earlier, the benefit of atomized objects is that when you use one of the axis methods that take an
XName as a parameter, the axis method only has to determine that two names reference the same instance to select
the desired elements.
The following example passes an XName to the Descendants method call, which then has better performance
because of the atomization pattern.
<C1>1</C1>
<C1>1</C1>
Pre-Atomization of XName Objects (LINQ to XML)
(C#)
9/3/2020 • 2 minutes to read • Edit Online
One way to improve performance in LINQ to XML is to pre-atomize XName objects. Pre-atomization means that
you assign a string to an XName object before you create the XML tree by using the constructors of the XElement
and XAttribute classes. Then, instead of passing a string to the constructor, which would use the implicit conversion
from string to XName, you pass the initialized XName object.
This improves performance when you create a large XML tree in which specific names are repeated. To do this, you
declare and initialize XName objects before you construct the XML tree, and then use the XName objects instead of
specifying strings for the element and attribute names. This technique can yield significant performance gains if
you are creating a large number of elements (or attributes) with the same name.
You should test pre-atomization with your scenario to decide if you should use it.
Example
The following example demonstrates this.
Console.WriteLine(root);
<Root>
<Data ID="1">4,100,000</Data>
<Data ID="2">3,700,000</Data>
<Data ID="3">1,150,000</Data>
</Root>
The following example shows the same technique where the XML document is in a namespace:
XNamespace aw = "http://www.adventure-works.com";
XName Root = aw + "Root";
XName Data = aw + "Data";
XName ID = "ID";
Console.WriteLine(root);
<aw:Root xmlns:aw="http://www.adventure-works.com">
<aw:Data ID="1">4,100,000</aw:Data>
<aw:Data ID="2">3,700,000</aw:Data>
<aw:Data ID="3">1,150,000</aw:Data>
</aw:Root>
The following example is more similar to what you will likely encounter in the real world. In this example, the
content of the element is supplied by a query:
DateTime t1 = DateTime.Now;
XElement root = new XElement(Root,
from i in System.Linq.Enumerable.Range(1, 100000)
select new XElement(Data,
new XAttribute(ID, i),
i * 5)
);
DateTime t2 = DateTime.Now;
The previous example performs better than the following example, in which names are not pre-atomized:
DateTime t1 = DateTime.Now;
XElement root = new XElement("Root",
from i in System.Linq.Enumerable.Range(1, 100000)
select new XElement("Data",
new XAttribute("ID", i),
i * 5)
);
DateTime t2 = DateTime.Now;
One of the most important performance benefits LINQ to XML, as opposed to XmlDocument, is that queries in LINQ
to XML are statically compiled, whereas XPath queries must be interpreted at run time. This feature is built in to
LINQ to XML, so you do not have to perform extra steps to take advantage of it, but it is helpful to understand the
distinction when choosing between the two technologies. This topic explains the difference.
XDocument po = XDocument.Load("PurchaseOrders.xml");
IEnumerable<XElement> list1 =
from el in po.Descendants("Address")
where (string)el.Attribute("Type") == "Shipping"
select el;
The query expression in this example is re-written by the compiler to method-based query syntax. The following
example, which is written in method-based query syntax, produces the same results as the previous one:
XDocument po = XDocument.Load("PurchaseOrders.xml");
IEnumerable<XElement> list1 =
po
.Descendants("Address")
.Where(el => (string)el.Attribute("Type") == "Shipping");
The Where method is an extension method. For more information, see Extension Methods. Because Where is an
extension method, the query above is compiled as though it were written as follows:
XDocument po = XDocument.Load("PurchaseOrders.xml");
IEnumerable<XElement> list1 =
System.Linq.Enumerable.Where(
po.Descendants("Address"),
el => (string)el.Attribute("Type") == "Shipping");
This example produces exactly the same results as the previous two examples. This illustrates the fact that queries
are effectively compiled into statically linked method calls. This, combined with the deferred execution semantics of
iterators, improves performance. For more information about the deferred execution semantics of iterators, see
Deferred Execution and Lazy Evaluation in LINQ to XML (C#).
NOTE
These examples are representative of the code that the compiler might write. The actual implementation might differ slightly
from these examples, but the performance will be the same or similar to these examples.
This query returns the same output as the examples that use LINQ to XML; the only difference is that LINQ to XML
indents the printed XML, whereas XmlDocument does not.
However, the XmlDocument approach generally does not perform as well as LINQ to XML, because the SelectNodes
method must do the following internally every time it is called:
It parses the string that contains the XPath expression, breaking the string into tokens.
It validates the tokens to make sure that the XPath expression is valid.
It translates the expression into an internal expression tree.
It iterates through the nodes, appropriately selecting the nodes for the result set based on the evaluation of
the expression.
This is significantly more than the work done by the corresponding LINQ to XML query. The specific performance
difference varies for different types of queries, but in general LINQ to XML queries do less work, and therefore
perform better, than evaluating XPath expressions using XmlDocument.
LINQ to XML Annotations
9/3/2020 • 2 minutes to read • Edit Online
Annotations in LINQ to XML enable you to associate any arbitrary object of any arbitrary type with any XML
component in an XML tree.
To add an annotation to an XML component, such as an XElement or XAttribute, you call the AddAnnotation
method. You retrieve annotations by type.
Note that annotations are not part of the XML infoset; they are not serialized or deserialized.
Methods
You can use the following methods when working with annotations:
M ET H O D DESC RIP T IO N
Annotation Gets the first annotation object of the specified type from an
XObject.
LINQ to XML events enable you to be notified when an XML tree is altered.
You can add events to an instance of any XObject. The event handler will then receive events for modifications to
that XObject and any of its descendants. For example, you can add an event handler to the root of the tree, and
handle all modifications to the tree from that event handler.
For examples of LINQ to XML events, see Changing and Changed.
The following events are raised when you modify an XML tree:
Example
Description
Events are useful when you want to maintain some aggregate information in an XML tree. For example, you may
want maintain an invoice total that is the sum of the line items of the invoice. This example uses events to maintain
the total of all of the child elements under the complex element Items .
Code
XElement root = new XElement("Root",
new XElement("Total", "0"),
new XElement("Items")
);
XElement total = root.Element("Total");
XElement items = root.Element("Items");
items.Changed += (object sender, XObjectChangeEventArgs cea) =>
{
switch (cea.ObjectChange)
{
case XObjectChange.Add:
if (sender is XElement)
total.Value = ((int)total + (int)(XElement)sender).ToString();
if (sender is XText)
total.Value = ((int)total + (int)((XText)sender).Parent).ToString();
break;
case XObjectChange.Remove:
if (sender is XElement)
total.Value = ((int)total - (int)(XElement)sender).ToString();
if (sender is XText)
total.Value = ((int)total - Int32.Parse(((XText)sender).Value)).ToString();
break;
}
Console.WriteLine("Changed {0} {1}",
sender.GetType().ToString(), cea.ObjectChange.ToString());
};
items.SetElementValue("Item1", 25);
items.SetElementValue("Item2", 50);
items.SetElementValue("Item2", 75);
items.SetElementValue("Item3", 133);
items.SetElementValue("Item1", null);
items.SetElementValue("Item4", 100);
Console.WriteLine("Total:{0}", (int)total);
Console.WriteLine(root);
Comments
This code produces the following output:
LINQ to XML developers who need to write programs such as an XML editor, a transform system, or a report writer
often need to write programs that work at a finer level of granularity than elements and attributes. They often need
to work at the node level, manipulating text nodes, processing instructions, and comments. This topic provides
some details about programming at the node level.
Node Details
There are a number of details of programming that a programmer working at the node level should know.
Parent Property of Children Nodes of XDocument is Set to Null
The Parent property contains the parent XElement, not the parent node. Child nodes of XDocument have no parent
XElement. Their parent is the document, so the Parent property for those nodes is set to null.
The following example demonstrates this:
True
True
Console.WriteLine(xmlTree.Nodes().OfType<XText>().Count());
// the following line does not cause the removal of the text node.
textNode.Value = "";
>><<
<Child1></Child1>
<Child2 />
xmlns="http://www.adventure-works.com" IsNamespaceDeclaration:True
xmlns:fc="www.fourthcoffee.com" IsNamespaceDeclaration:True
AnAttribute="abc" IsNamespaceDeclaration:False
<Root/>
<!--a comment-->
", LoadOptions.PreserveWhitespace);
3
0
// this shows that there is only one child node of the document
Console.WriteLine(doc.Nodes().Count());
LINQ to XML contains various methods that allow you to modify an XML tree directly. You can add elements, delete
elements, change the contents of an element, add attributes, and so on. This programming interface is described in
Modifying XML Trees (LINQ to XML) (C#). If you are iterating through one of the axes, such as Elements, and you are
modifying the XML tree as you iterate through the axis, you can end up with some strange bugs.
This problem is sometimes known as "The Halloween Problem".
Now, suppose that you want to move through the linked list, adding three new items (a', b', and c'). You want the
resulting linked list to look like this:
a -> a' -> b -> b' -> c -> c'
So you write code that iterates through the list, and for every item, adds a new item right after it. What happens is
that your code will first see the a element, and insert a' after it. Now, your code will move to the next node in the
list, which is now a' ! It happily adds a new item to the list, a'' .
How would you solve this in the real world? Well, you might make a copy of the original linked list, and create a
completely new list. Or if you are writing purely imperative code, you might find the first item, add the new item,
and then advance twice in the linked list, advancing over the element that you just added.
This code goes into an infinite loop. The foreach statement iterates through the Elements() axis, adding new
elements to the doc element. It ends up iterating also through the elements it just added. And because it allocates
new objects with every iteration of the loop, it will eventually consume all available memory.
You can fix this problem by pulling the collection into memory using the ToList standard query operator, as follows:
Now the code works. The resulting XML tree is the following:
<Root>
<A>1</A>
<B>2</B>
<C>3</C>
<A>1</A>
<B>2</B>
<C>3</C>
</Root>
However, this does not do what you want. In this situation, after you have removed the first element, A, it is
removed from the XML tree contained in root, and the code in the Elements method that is doing the iterating
cannot find the next element.
The preceding code produces the following output:
<Root>
<B>2</B>
<C>3</C>
</Root>
<Root />
Alternatively, you can eliminate the iteration altogether by calling RemoveAll on the parent element:
var z =
from e in root.Elements()
where TestSomeCondition(e)
select DoMyProjection(e);
Such analysis code would need to analyze the methods TestSomeCondition and DoMyProjection, and all methods
that those methods called, to determine if any code had side-effects. But the analysis code could not just look for
any code that had side-effects. It would need to select for just the code that had side-effects on the child elements
of root in this situation.
LINQ to XML does not attempt to do any such analysis.
It is up to you to avoid these problems.
Guidance
First, do not mix declarative and imperative code.
Even if you know exactly the semantics of your collections and the semantics of the methods that modify the XML
tree, if you write some clever code that avoids these categories of problems, your code will need to be maintained
by other developers in the future, and they may not be as clear on the issues. If you mix declarative and imperative
coding styles, your code will be more brittle.
If you write code that materializes a collection so that these problems are avoided, note it with comments as
appropriate in your code, so that maintenance programmers will understand the issue.
Second, if performance and other considerations allow, use only declarative code. Don't modify your existing XML
tree. Generate a new one.
Sometimes you have to read arbitrarily large XML files, and write your application so that the memory footprint of
the application is predictable. If you attempt to populate an XML tree with a large XML file, your memory usage will
be proportional to the size of the file—that is, excessive. Therefore, you should use a streaming technique instead.
One option is to write your application using XmlReader. However, you might want to use LINQ to query the XML
tree. If this is the case, you can write your own custom axis method. For more information, see How to write a LINQ
to XML axis method (C#).
To write your own axis method, you write a small method that uses the XmlReader to read nodes until it reaches
one of the nodes in which you are interested. The method then calls ReadFrom, which reads from the XmlReader
and instantiates an XML fragment. It then yields each fragment through yield return to the method that is
enumerating your custom axis method. You can then write LINQ queries on your custom axis method.
Streaming techniques are best applied in situations where you need to process the source document only once,
and you can process the elements in document order. Certain standard query operators, such as OrderBy, iterate
their source, collect all of the data, sort it, and then finally yield the first item in the sequence. If you use a query
operator that materializes its source before yielding the first item, you will not retain a small memory footprint.
Example
Sometimes the problem gets just a little more interesting. In the following XML document, the consumer of your
custom axis method also has to know the name of the customer that each item belongs to.
<?xml version="1.0" encoding="utf-8" ?>
<Root>
<Customer>
<Name>A. Datum Corporation</Name>
<Item>
<Key>0001</Key>
</Item>
<Item>
<Key>0002</Key>
</Item>
<Item>
<Key>0003</Key>
</Item>
<Item>
<Key>0004</Key>
</Item>
</Customer>
<Customer>
<Name>Fabrikam, Inc.</Name>
<Item>
<Key>0005</Key>
</Item>
<Item>
<Key>0006</Key>
</Item>
<Item>
<Key>0007</Key>
</Item>
<Item>
<Key>0008</Key>
</Item>
</Customer>
<Customer>
<Name>Southridge Video</Name>
<Item>
<Key>0009</Key>
</Item>
<Item>
<Key>0010</Key>
</Item>
</Customer>
</Root>
The approach that this example takes is to also watch for this header information, save the header information, and
then build a small XML tree that contains both the header information and the detail that you are enumerating. The
axis method then yields this new, small XML tree. The query then has access to the header information as well as
the detail information.
This approach has a small memory footprint. As each detail XML fragment is yielded, no references are kept to the
previous fragment, and it is available for garbage collection. This technique creates many short lived objects on the
heap.
The following example shows how to implement and use a custom axis method that streams XML fragments from
the file specified by the URI. This custom axis is written such that it expects a document that has Customer , Name ,
and Item elements, and that those elements will be arranged as in the above Source.xml document. It is a
simplistic implementation. A more robust implementation would be prepared to parse an invalid document.
static IEnumerable<XElement> StreamCustomerItem(string uri)
{
using (XmlReader reader = XmlReader.Create(uri))
{
XElement name = null;
XElement item = null;
reader.MoveToContent();
// Parse the file, save header information when encountered, and yield the
// Item XElement objects as they are created.
Sometimes you have to transform large XML files, and write your application so that the memory footprint of the
application is predictable. If you try to populate an XML tree with a very large XML file, your memory usage will be
proportional to the size of the file (that is, excessive). Therefore, you should use a streaming technique instead.
Streaming techniques are best applied in situations where you need to process the source document only once, and
you can process the elements in document order. Certain standard query operators, such as OrderBy, iterate their
source, collect all of the data, sort it, and then finally yield the first item in the sequence. Note that if you use a
query operator that materializes its source before yielding the first item, you will not retain a small memory
footprint for your application.
Even if you use the technique described in How to stream XML fragments with access to header information (C#), if
you try to assemble an XML tree that contains the transformed document, memory usage will be too great.
There are two main approaches. One approach is to use the deferred processing characteristics of
XStreamingElement. Another approach is to create an XmlWriter, and use the capabilities of LINQ to XML to write
elements to an XmlWriter. This topic demonstrates both approaches.
Example
The following example builds on the example in How to stream XML fragments with access to header information
(C#).
This example uses the deferred execution capabilities of XStreamingElement to stream the output. This example can
transform a very large document while maintaining a small memory footprint.
Note that the custom axis ( StreamCustomerItem ) is specifically written so that it expects a document that has
Customer , Name , and Item elements, and that those elements will be arranged as in the following Source.xml
document. A more robust implementation, however, would be prepared to parse an invalid document.
The following is the source document, Source.xml:
<?xml version="1.0" encoding="utf-8" ?>
<Root>
<Customer>
<Name>A. Datum Corporation</Name>
<Item>
<Key>0001</Key>
</Item>
<Item>
<Key>0002</Key>
</Item>
<Item>
<Key>0003</Key>
</Item>
<Item>
<Key>0004</Key>
</Item>
</Customer>
<Customer>
<Name>Fabrikam, Inc.</Name>
<Item>
<Key>0005</Key>
</Item>
<Item>
<Key>0006</Key>
</Item>
<Item>
<Key>0007</Key>
</Item>
<Item>
<Key>0008</Key>
</Item>
</Customer>
<Customer>
<Name>Southridge Video</Name>
<Item>
<Key>0009</Key>
</Item>
<Item>
<Key>0010</Key>
</Item>
</Customer>
</Root>
static IEnumerable<XElement> StreamCustomerItem(string uri)
{
using (XmlReader reader = XmlReader.Create(uri))
{
XElement name = null;
XElement item = null;
reader.MoveToContent();
// Parse the file, save header information when encountered, and yield the
// Item XElement objects as they are created.
Example
The following example also builds on the example in How to stream XML fragments with access to header
information (C#).
This example uses the capability of LINQ to XML to write elements to an XmlWriter. This example can transform a
very large document while maintaining a small memory footprint.
Note that the custom axis ( StreamCustomerItem ) is specifically written so that it expects a document that has
Customer , Name , and Item elements, and that those elements will be arranged as in the following Source.xml
document. A more robust implementation, however, would either validate the source document with an XSD, or
would be prepared to parse an invalid document.
This example uses the same source document, Source.xml, as the previous example in this topic. It also produces
exactly the same output.
Using XStreamingElement for streaming the output XML is preferred over writing to an XmlWriter.
static IEnumerable<XElement> StreamCustomerItem(string uri)
{
using (XmlReader reader = XmlReader.Create(uri))
{
XElement name = null;
XElement item = null;
reader.MoveToContent();
// Parse the file, save header information when encountered, and yield the
// Item XElement objects as they are created.
<Root>
<Item>
<Customer>A. Datum Corporation</Customer>
<Key>0001</Key>
</Item>
<Item>
<Customer>A. Datum Corporation</Customer>
<Key>0002</Key>
</Item>
<Item>
<Customer>A. Datum Corporation</Customer>
<Key>0003</Key>
</Item>
<Item>
<Customer>A. Datum Corporation</Customer>
<Key>0004</Key>
</Item>
<Item>
<Customer>Fabrikam, Inc.</Customer>
<Key>0005</Key>
</Item>
<Item>
<Customer>Fabrikam, Inc.</Customer>
<Key>0006</Key>
</Item>
<Item>
<Customer>Fabrikam, Inc.</Customer>
<Key>0007</Key>
</Item>
<Item>
<Customer>Fabrikam, Inc.</Customer>
<Key>0008</Key>
</Item>
<Item>
<Customer>Southridge Video</Customer>
<Key>0009</Key>
</Item>
<Item>
<Customer>Southridge Video</Customer>
<Key>0010</Key>
</Item>
</Root>
How to read and write an encoded document (C#)
9/3/2020 • 2 minutes to read • Edit Online
To create an encoded XML document, you add an XDeclaration to the XML tree, setting the encoding to the desired
code page name.
Any value returned by WebName is a valid value.
If you read an encoded document, the Encoding property will be set to the code page name.
If you set Encoding to a valid code page name, LINQ to XML will serialize with the specified encoding.
Example
The following example creates two documents, one with utf-8 encoding, and one with utf-16 encoding. It then loads
the documents and prints the encoding to the console.
Encoded document:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Root>Content</Root>
Encoded document:
<?xml version="1.0" encoding="utf-16" standalone="yes"?>
<Root>Content</Root>
See also
XDeclaration.Encoding
Using XSLT to Transform an XML Tree (C#)
9/3/2020 • 2 minutes to read • Edit Online
You can create an XML tree, create an XmlReader from the XML tree, create a new document, and create an
XmlWriter that will write into the new document. Then, you can invoke the XSLT transformation, passing the
XmlReader and XmlWriter to the transformation. After the transformation successfully completes, the new XML tree
is populated with the results of the transform.
Example
string xslt = @"<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='1.0'>
<xsl:template match='/Parent'>
<Root>
<C1>
<xsl:value-of select='Child1'/>
</C1>
<C2>
<xsl:value-of select='Child2'/>
</C2>
</Root>
</xsl:template>
</xsl:stylesheet>";
See also
XContainer.CreateWriter
XNode.CreateReader
How to use annotations to transform LINQ to XML
trees in an XSLT style (C#)
9/3/2020 • 7 minutes to read • Edit Online
For any given text node, there may be any number of child <b> and <i> elements. This approach extends to a
number of other situations, such as pages that can contain a variety of child elements, such as regular paragraphs,
bulleted paragraphs, and bitmaps. Cells in a table may contain text, drop down lists, or bitmaps. One of the primary
characteristics of document centric XML is that you do not know which child element any particular element will
have.
If you want to transform elements in a tree where you don't necessarily know much about the children of the
elements that you want to transform, then this approach that uses annotations is an effective approach.
The summary of the approach is:
First, annotate elements in the tree with a replacement element.
Second, iterate through the entire tree, creating a new tree where you replace each element with its
annotation. This example implements the iteration and creation of the new tree in a function named XForm .
In detail, the approach consists of:
Execute one or more LINQ to XML queries that return the set of elements that you want to transform from
one shape to another. For each element in the query, add a new XElement object as an annotation to the
element. This new element will replace the annotated element in the new, transformed tree. This is simple
code to write, as demonstrated by the example.
The new element that is added as an annotation can contain new child nodes; it can form a sub-tree with any
desired shape.
There is a special rule: If a child node of the new element is in a different namespace, a namespace that is
made up for this purpose (in this example, the namespace is
http://www.microsoft.com/LinqToXmlTransform/2007 ), then that child element is not copied to the new tree.
Instead, if the namespace is the above mentioned special namespace, and the local name of the element is
ApplyTransforms , then the child nodes of the element in the source tree are iterated, and copied to the new
tree (with the exception that annotated child elements are themselves transformed according to these rules).
This is somewhat analogous to the specification of transforms in XSL. The query that selects a set of nodes is
analogous to the XPath expression for a template. The code to create the new XElement that is saved as an
annotation is analogous to the sequence constructor in XSL, and the ApplyTransforms element is analogous
in function to the xsl:apply-templates element in XSL.
One advantage to taking this approach - as you formulate queries, you are always writing queries on the
unmodified source tree. You need not worry about how modifications to the tree affect the queries that you
are writing.
Transforming a Tree
This first example renames all Paragraph nodes to para .
XNamespace xf = "http://www.microsoft.com/LinqToXmlTransform/2007";
XName at = xf + "ApplyTransforms";
// The XForm method, shown later in this topic, accomplishes the transform
XElement newRoot = XForm(root);
Console.WriteLine(newRoot);
<Root>
<para>This is a sentence with <b>bold</b> and <i>italic</i> text.</para>
<para>More text.</para>
</Root>
// while adding annotations, you can query the source tree all you want,
// as the tree is not mutated while annotating.
var avg = data.Elements("Data").Select(z => (Decimal)z).Average();
data.AddAnnotation(
new XElement("Root",
new XElement(xf + "ApplyTransforms"),
new XElement("Average", $"{avg:F4}"),
new XElement("Sum",
data
.Elements("Data")
.Select(z => (int)z)
.Sum()
)
)
);
Console.WriteLine("Before Transform");
Console.WriteLine("----------------");
Console.WriteLine(data);
Console.WriteLine();
Console.WriteLine();
// The XForm method, shown later in this topic, accomplishes the transform
XElement newData = XForm(data);
Console.WriteLine("After Transform");
Console.WriteLine("----------------");
Console.WriteLine(newData);
Before Transform
----------------
<Root>
<Data>20</Data>
<Data>10</Data>
<Data>3</Data>
</Root>
After Transform
----------------
<Root>
<Data>20</Data>
<Data>10</Data>
<Data>3</Data>
<Average>11.0000</Average>
<Sum>33</Sum>
</Root>
if (source.Annotation<XElement>() != null)
{
XElement anno = source.Annotation<XElement>();
return new XElement(anno.Name,
anno.Attributes(),
anno
.Nodes()
.Select(
(XNode n) =>
{
XElement annoEl = n as XElement;
if (annoEl != null)
{
if (annoEl.Name == at)
return (object)(
source.Nodes()
.Select(
(XNode n2) =>
{
XElement e2 = n2 as XElement;
if (e2 == null)
return n2;
else
return XForm(e2);
}
)
);
else
return n;
}
else
return n;
}
)
);
}
else
{
return new XElement(source.Name,
source.Attributes(),
source
.Nodes()
.Select(n =>
{
XElement el = n as XElement;
if (el == null)
return n;
else
return XForm(el);
}
)
);
}
}
Complete Example
The following code is a complete example that includes the XForm function. It includes a few of the typical uses of
this type of transform:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
class Program
{
static XNamespace xf = "http://www.microsoft.com/LinqToXmlTransform/2007";
static XName at = xf + "ApplyTransforms";
// replace Other with NewOther, add new child elements around original content
foreach (var el in root.Elements("Other"))
el.AddAnnotation(
new XElement("NewOther",
new XElement("MyNewChild", 1),
// same idea as xsl:apply-templates
new XElement(xf + "ApplyTransforms"),
new XElement("ChildThatComesAfter")
)
);
Console.WriteLine("After Transform");
Console.WriteLine("----------------");
Console.WriteLine(newRoot);
}
}
Before Transform
----------------
<Root Att1="123">
<!--A comment-->
<Child>1</Child>
<Child>2</Child>
<Other>
<GC>3</GC>
<GC>4</GC>
</Other>
<SomeMixedContent>This is <i>an</i> element that <b>has</b> some mixed content</SomeMixedContent>
<AnUnchangedElement>42</AnUnchangedElement>
</Root>
After Transform
----------------
<Root Att1="123">
<!--A comment-->
<NewChild>1</NewChild>
<NewChild>2</NewChild>
<NewOther>
<MyNewChild>1</MyNewChild>
<GrandChild ANewAttribute="999">3</GrandChild>
<GC>4</GC>
<ChildThatComesAfter />
</NewOther>
<MixedContent>This is <Italic>an</Italic> element that <Bold>has</Bold> some mixed content</MixedContent>
<AnUnchangedElement>42</AnUnchangedElement>
</Root>
How to serialize using XmlSerializer (C#)
9/3/2020 • 2 minutes to read • Edit Online
This topic shows an example that serializes and deserializes using XmlSerializer.
Example
The following example creates a number of objects that contain XElement objects. It then serializes them to a
memory stream, and then deserializes them from the memory stream.
using System;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.Linq;
public XElementContainer()
{
member = XLinqTest.CreateXElement();
}
public XElementNullContainer()
{
}
}
class XLinqTest
{
static void Main(string[] args)
{
Test<XElementNullContainer>(new XElementNullContainer());
Test<XElement>(CreateXElement());
Test<XElementContainer>(new XElementContainer());
}
This topic shows an example that serializes and deserializes using DataContractSerializer.
Example
The following example creates a number of objects that contain XElement objects. It then serializes them to text files,
and then deserializes them from the text files.
using System;
using System.Xml;
using System.Xml.Linq;
using System.IO;
using System.Runtime.Serialization;
[DataContract]
public class XElementContainer
{
[DataMember]
public XElement member;
public XElementContainer()
{
member = XLinqTest.CreateXElement();
}
}
[DataContract]
public class XElementNullContainer
{
[DataMember]
public XElement member;
public XElementNullContainer()
{
member = null;
}
}
This topic describes security issues associated with LINQ to XML. In addition, it provides some guidance for
mitigating security exposure.
See also
Programming Guide (LINQ to XML) (C#)
Sample XML File: Typical Purchase Order (LINQ to
XML)
9/3/2020 • 2 minutes to read • Edit Online
The following XML file is used in various examples in the LINQ to XML documentation. This file is a typical
purchase order.
PurchaseOrder.xml
<?xml version="1.0"?>
<PurchaseOrder PurchaseOrderNumber="99503" OrderDate="1999-10-20">
<Address Type="Shipping">
<Name>Ellen Adams</Name>
<Street>123 Maple Street</Street>
<City>Mill Valley</City>
<State>CA</State>
<Zip>10999</Zip>
<Country>USA</Country>
</Address>
<Address Type="Billing">
<Name>Tai Yee</Name>
<Street>8 Oak Avenue</Street>
<City>Old Town</City>
<State>PA</State>
<Zip>95819</Zip>
<Country>USA</Country>
</Address>
<DeliveryNotes>Please leave packages in shed by driveway.</DeliveryNotes>
<Items>
<Item PartNumber="872-AA">
<ProductName>Lawnmower</ProductName>
<Quantity>1</Quantity>
<USPrice>148.95</USPrice>
<Comment>Confirm this is electric</Comment>
</Item>
<Item PartNumber="926-AA">
<ProductName>Baby Monitor</ProductName>
<Quantity>2</Quantity>
<USPrice>39.98</USPrice>
<ShipDate>1999-05-21</ShipDate>
</Item>
</Items>
</PurchaseOrder>
Sample XML File: Typical Purchase Order in a
Namespace
9/3/2020 • 2 minutes to read • Edit Online
The following XML file is used in various examples in the LINQ to XML documentation. This file is a typical
purchase order. The XML is in a namespace.
PurchaseOrderInNamespace.xml
<?xml version="1.0"?>
<aw:PurchaseOrder
aw:PurchaseOrderNumber="99503"
aw:OrderDate="1999-10-20"
xmlns:aw="http://www.adventure-works.com">
<aw:Address aw:Type="Shipping">
<aw:Name>Ellen Adams</aw:Name>
<aw:Street>123 Maple Street</aw:Street>
<aw:City>Mill Valley</aw:City>
<aw:State>CA</aw:State>
<aw:Zip>10999</aw:Zip>
<aw:Country>USA</aw:Country>
</aw:Address>
<aw:Address aw:Type="Billing">
<aw:Name>Tai Yee</aw:Name>
<aw:Street>8 Oak Avenue</aw:Street>
<aw:City>Old Town</aw:City>
<aw:State>PA</aw:State>
<aw:Zip>95819</aw:Zip>
<aw:Country>USA</aw:Country>
</aw:Address>
<aw:DeliveryNotes>Please leave packages in shed by driveway.</aw:DeliveryNotes>
<aw:Items>
<aw:Item aw:PartNumber="872-AA">
<aw:ProductName>Lawnmower</aw:ProductName>
<aw:Quantity>1</aw:Quantity>
<aw:USPrice>148.95</aw:USPrice>
<aw:Comment>Confirm this is electric</aw:Comment>
</aw:Item>
<aw:Item aw:PartNumber="926-AA">
<aw:ProductName>Baby Monitor</aw:ProductName>
<aw:Quantity>2</aw:Quantity>
<aw:USPrice>39.98</aw:USPrice>
<aw:ShipDate>1999-05-21</aw:ShipDate>
</aw:Item>
</aw:Items>
</aw:PurchaseOrder>
Sample XML File: Multiple Purchase Orders (LINQ to
XML)
9/3/2020 • 2 minutes to read • Edit Online
The following XML file is used in various examples in the LINQ to XML documentation. This file contains several
purchase orders.
PurchaseOrders.xml
<?xml version="1.0"?>
<PurchaseOrders>
<PurchaseOrder PurchaseOrderNumber="99503" OrderDate="1999-10-20">
<Address Type="Shipping">
<Name>Ellen Adams</Name>
<Street>123 Maple Street</Street>
<City>Mill Valley</City>
<State>CA</State>
<Zip>10999</Zip>
<Country>USA</Country>
</Address>
<Address Type="Billing">
<Name>Tai Yee</Name>
<Street>8 Oak Avenue</Street>
<City>Old Town</City>
<State>PA</State>
<Zip>95819</Zip>
<Country>USA</Country>
</Address>
<DeliveryNotes>Please leave packages in shed by driveway.</DeliveryNotes>
<Items>
<Item PartNumber="872-AA">
<ProductName>Lawnmower</ProductName>
<Quantity>1</Quantity>
<USPrice>148.95</USPrice>
<Comment>Confirm this is electric</Comment>
</Item>
<Item PartNumber="926-AA">
<ProductName>Baby Monitor</ProductName>
<Quantity>2</Quantity>
<USPrice>39.98</USPrice>
<ShipDate>1999-05-21</ShipDate>
</Item>
</Items>
</PurchaseOrder>
<PurchaseOrder PurchaseOrderNumber="99505" OrderDate="1999-10-22">
<Address Type="Shipping">
<Name>Cristian Osorio</Name>
<Street>456 Main Street</Street>
<City>Buffalo</City>
<State>NY</State>
<Zip>98112</Zip>
<Country>USA</Country>
</Address>
<Address Type="Billing">
<Name>Cristian Osorio</Name>
<Street>456 Main Street</Street>
<City>Buffalo</City>
<State>NY</State>
<Zip>98112</Zip>
<Country>USA</Country>
<Country>USA</Country>
</Address>
<DeliveryNotes>Please notify me before shipping.</DeliveryNotes>
<Items>
<Item PartNumber="456-NM">
<ProductName>Power Supply</ProductName>
<Quantity>1</Quantity>
<USPrice>45.99</USPrice>
</Item>
</Items>
</PurchaseOrder>
<PurchaseOrder PurchaseOrderNumber="99504" OrderDate="1999-10-22">
<Address Type="Shipping">
<Name>Jessica Arnold</Name>
<Street>4055 Madison Ave</Street>
<City>Seattle</City>
<State>WA</State>
<Zip>98112</Zip>
<Country>USA</Country>
</Address>
<Address Type="Billing">
<Name>Jessica Arnold</Name>
<Street>4055 Madison Ave</Street>
<City>Buffalo</City>
<State>NY</State>
<Zip>98112</Zip>
<Country>USA</Country>
</Address>
<Items>
<Item PartNumber="898-AZ">
<ProductName>Computer Keyboard</ProductName>
<Quantity>1</Quantity>
<USPrice>29.99</USPrice>
</Item>
<Item PartNumber="898-AM">
<ProductName>Wireless Mouse</ProductName>
<Quantity>1</Quantity>
<USPrice>14.99</USPrice>
</Item>
</Items>
</PurchaseOrder>
</PurchaseOrders>
Sample XML File: Multiple Purchase Orders in a
Namespace
9/3/2020 • 2 minutes to read • Edit Online
The following XML file is used in various examples in the LINQ to XML documentation. This file contains several
purchase orders. The XML is in a namespace.
PurchaseOrdersInNamespace.xml
<?xml version="1.0" encoding="utf-8"?>
<aw:PurchaseOrders xmlns:aw="http://www.adventure-works.com">
<aw:PurchaseOrder aw:PurchaseOrderNumber="99503" aw:OrderDate="1999-10-20">
<aw:Address aw:Type="Shipping">
<aw:Name>Ellen Adams</aw:Name>
<aw:Street>123 Maple Street</aw:Street>
<aw:City>Mill Valley</aw:City>
<aw:State>CA</aw:State>
<aw:Zip>10999</aw:Zip>
<aw:Country>USA</aw:Country>
</aw:Address>
<aw:Address aw:Type="Billing">
<aw:Name>Tai Yee</aw:Name>
<aw:Street>8 Oak Avenue</aw:Street>
<aw:City>Old Town</aw:City>
<aw:State>PA</aw:State>
<aw:Zip>95819</aw:Zip>
<aw:Country>USA</aw:Country>
</aw:Address>
<aw:DeliveryNotes>Please leave packages in shed by driveway.</aw:DeliveryNotes>
<aw:Items>
<aw:Item aw:PartNumber="872-AA">
<aw:ProductName>Lawnmower</aw:ProductName>
<aw:Quantity>1</aw:Quantity>
<aw:USPrice>148.95</aw:USPrice>
<aw:Comment>Confirm this is electric</aw:Comment>
</aw:Item>
<aw:Item aw:PartNumber="926-AA">
<aw:ProductName>Baby Monitor</aw:ProductName>
<aw:Quantity>2</aw:Quantity>
<aw:USPrice>39.98</aw:USPrice>
<aw:ShipDate>1999-05-21</aw:ShipDate>
</aw:Item>
</aw:Items>
</aw:PurchaseOrder>
<aw:PurchaseOrder aw:PurchaseOrderNumber="99505" aw:OrderDate="1999-10-22">
<aw:Address aw:Type="Shipping">
<aw:Name>Cristian Osorio</aw:Name>
<aw:Street>456 Main Street</aw:Street>
<aw:City>Buffalo</aw:City>
<aw:State>NY</aw:State>
<aw:Zip>98112</aw:Zip>
<aw:Country>USA</aw:Country>
</aw:Address>
<aw:Address aw:Type="Billing">
<aw:Name>Cristian Osorio</aw:Name>
<aw:Street>456 Main Street</aw:Street>
<aw:City>Buffalo</aw:City>
<aw:State>NY</aw:State>
<aw:Zip>98112</aw:Zip>
<aw:Country>USA</aw:Country>
<aw:Country>USA</aw:Country>
</aw:Address>
<aw:DeliveryNotes>Please notify me before shipping.</aw:DeliveryNotes>
<aw:Items>
<aw:Item aw:PartNumber="456-NM">
<aw:ProductName>Power Supply</aw:ProductName>
<aw:Quantity>1</aw:Quantity>
<aw:USPrice>45.99</aw:USPrice>
</aw:Item>
</aw:Items>
</aw:PurchaseOrder>
<aw:PurchaseOrder aw:PurchaseOrderNumber="99504" aw:OrderDate="1999-10-22">
<aw:Address aw:Type="Shipping">
<aw:Name>Jessica Arnold</aw:Name>
<aw:Street>4055 Madison Ave</aw:Street>
<aw:City>Seattle</aw:City>
<aw:State>WA</aw:State>
<aw:Zip>98112</aw:Zip>
<aw:Country>USA</aw:Country>
</aw:Address>
<aw:Address aw:Type="Billing">
<aw:Name>Jessica Arnold</aw:Name>
<aw:Street>4055 Madison Ave</aw:Street>
<aw:City>Buffalo</aw:City>
<aw:State>NY</aw:State>
<aw:Zip>98112</aw:Zip>
<aw:Country>USA</aw:Country>
</aw:Address>
<aw:Items>
<aw:Item aw:PartNumber="898-AZ">
<aw:ProductName>Computer Keyboard</aw:ProductName>
<aw:Quantity>1</aw:Quantity>
<aw:USPrice>29.99</aw:USPrice>
</aw:Item>
<aw:Item aw:PartNumber="898-AM">
<aw:ProductName>Wireless Mouse</aw:ProductName>
<aw:Quantity>1</aw:Quantity>
<aw:USPrice>14.99</aw:USPrice>
</aw:Item>
</aw:Items>
</aw:PurchaseOrder>
</aw:PurchaseOrders>
Sample XML File: Test Configuration (LINQ to XML)
9/3/2020 • 2 minutes to read • Edit Online
The following XML file is used in various examples in the LINQ to XML documentation. This is a test configuration
file.
TestConfig.xml
<?xml version="1.0"?>
<Tests>
<Test TestId="0001" TestType="CMD">
<Name>Convert number to string</Name>
<CommandLine>Examp1.EXE</CommandLine>
<Input>1</Input>
<Output>One</Output>
</Test>
<Test TestId="0002" TestType="CMD">
<Name>Find succeeding characters</Name>
<CommandLine>Examp2.EXE</CommandLine>
<Input>abc</Input>
<Output>def</Output>
</Test>
<Test TestId="0003" TestType="GUI">
<Name>Convert multiple numbers to strings</Name>
<CommandLine>Examp2.EXE /Verbose</CommandLine>
<Input>123</Input>
<Output>One Two Three</Output>
</Test>
<Test TestId="0004" TestType="GUI">
<Name>Find correlated key</Name>
<CommandLine>Examp3.EXE</CommandLine>
<Input>a1</Input>
<Output>b1</Output>
</Test>
<Test TestId="0005" TestType="GUI">
<Name>Count characters</Name>
<CommandLine>FinalExamp.EXE</CommandLine>
<Input>This is a test</Input>
<Output>14</Output>
</Test>
<Test TestId="0006" TestType="GUI">
<Name>Another Test</Name>
<CommandLine>Examp2.EXE</CommandLine>
<Input>Test Input</Input>
<Output>10</Output>
</Test>
</Tests>
Sample XML File: Test Configuration in a Namespace
9/3/2020 • 2 minutes to read • Edit Online
The following XML file is used in various examples in the LINQ to XML documentation. This is a test configuration
file. The XML is in a namespace.
TestConfigInNamespace.xml
<?xml version="1.0"?>
<Tests xmlns="http://www.adatum.com">
<Test TestId="0001" TestType="CMD">
<Name>Convert number to string</Name>
<CommandLine>Examp1.EXE</CommandLine>
<Input>1</Input>
<Output>One</Output>
</Test>
<Test TestId="0002" TestType="CMD">
<Name>Find succeeding characters</Name>
<CommandLine>Examp2.EXE</CommandLine>
<Input>abc</Input>
<Output>def</Output>
</Test>
<Test TestId="0003" TestType="GUI">
<Name>Convert multiple numbers to strings</Name>
<CommandLine>Examp2.EXE /Verbose</CommandLine>
<Input>123</Input>
<Output>One Two Three</Output>
</Test>
<Test TestId="0004" TestType="GUI">
<Name>Find correlated key</Name>
<CommandLine>Examp3.EXE</CommandLine>
<Input>a1</Input>
<Output>b1</Output>
</Test>
<Test TestId="0005" TestType="GUI">
<Name>Count characters</Name>
<CommandLine>FinalExamp.EXE</CommandLine>
<Input>This is a test</Input>
<Output>14</Output>
</Test>
<Test TestId="0006" TestType="GUI">
<Name>Another Test</Name>
<CommandLine>Examp2.EXE</CommandLine>
<Input>Test Input</Input>
<Output>10</Output>
</Test>
</Tests>
Sample XML File: Customers and Orders (LINQ to
XML)
9/3/2020 • 3 minutes to read • Edit Online
The following XML file is used in various examples in the LINQ to XML documentation. This file contains
customers and orders.
The topic Sample XSD File: Customers and Orders contains an XSD that can be used to validate this document. It
uses the xs:key and xs:keyref features of XSD to establish that the CustomerID attribute of the Customer
element is a key, and to establish a relationship between the CustomerID element in each Order element and
the CustomerID attribute in each Customer element.
For an example of writing LINQ queries that take advantage of this relationship using the Join clause, see How
to join two collections (LINQ to XML) (C#).
CustomersOrders.xml
<?xml version="1.0" encoding="utf-8"?>
<Root>
<Customers>
<Customer CustomerID="GREAL">
<CompanyName>Great Lakes Food Market</CompanyName>
<ContactName>Howard Snyder</ContactName>
<ContactTitle>Marketing Manager</ContactTitle>
<Phone>(503) 555-7555</Phone>
<FullAddress>
<Address>2732 Baker Blvd.</Address>
<City>Eugene</City>
<Region>OR</Region>
<PostalCode>97403</PostalCode>
<Country>USA</Country>
</FullAddress>
</Customer>
<Customer CustomerID="HUNGC">
<CompanyName>Hungry Coyote Import Store</CompanyName>
<ContactName>Yoshi Latimer</ContactName>
<ContactTitle>Sales Representative</ContactTitle>
<Phone>(503) 555-6874</Phone>
<Fax>(503) 555-2376</Fax>
<FullAddress>
<Address>City Center Plaza 516 Main St.</Address>
<City>Elgin</City>
<Region>OR</Region>
<PostalCode>97827</PostalCode>
<Country>USA</Country>
</FullAddress>
</Customer>
<Customer CustomerID="LAZYK">
<CompanyName>Lazy K Kountry Store</CompanyName>
<ContactName>John Steel</ContactName>
<ContactTitle>Marketing Manager</ContactTitle>
<Phone>(509) 555-7969</Phone>
<Fax>(509) 555-6221</Fax>
<FullAddress>
<Address>12 Orchestra Terrace</Address>
<City>Walla Walla</City>
<Region>WA</Region>
<PostalCode>99362</PostalCode>
<Country>USA</Country>
</FullAddress>
</Customer>
<Customer CustomerID="LETSS">
<CompanyName>Let's Stop N Shop</CompanyName>
<ContactName>Jaime Yorres</ContactName>
<ContactTitle>Owner</ContactTitle>
<Phone>(415) 555-5938</Phone>
<FullAddress>
<Address>87 Polk St. Suite 5</Address>
<City>San Francisco</City>
<Region>CA</Region>
<PostalCode>94117</PostalCode>
<Country>USA</Country>
</FullAddress>
</Customer>
</Customers>
<Orders>
<Order>
<CustomerID>GREAL</CustomerID>
<EmployeeID>6</EmployeeID>
<OrderDate>1997-05-06T00:00:00</OrderDate>
<RequiredDate>1997-05-20T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-05-09T00:00:00">
<ShipVia>2</ShipVia>
<Freight>3.35</Freight>
<ShipName>Great Lakes Food Market</ShipName>
<ShipAddress>2732 Baker Blvd.</ShipAddress>
<ShipCity>Eugene</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97403</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>GREAL</CustomerID>
<EmployeeID>8</EmployeeID>
<OrderDate>1997-07-04T00:00:00</OrderDate>
<RequiredDate>1997-08-01T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-07-14T00:00:00">
<ShipVia>2</ShipVia>
<Freight>4.42</Freight>
<ShipName>Great Lakes Food Market</ShipName>
<ShipAddress>2732 Baker Blvd.</ShipAddress>
<ShipCity>Eugene</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97403</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>GREAL</CustomerID>
<EmployeeID>1</EmployeeID>
<OrderDate>1997-07-31T00:00:00</OrderDate>
<RequiredDate>1997-08-28T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-08-05T00:00:00">
<ShipVia>2</ShipVia>
<Freight>116.53</Freight>
<ShipName>Great Lakes Food Market</ShipName>
<ShipAddress>2732 Baker Blvd.</ShipAddress>
<ShipCity>Eugene</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97403</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>GREAL</CustomerID>
<EmployeeID>4</EmployeeID>
<EmployeeID>4</EmployeeID>
<OrderDate>1997-07-31T00:00:00</OrderDate>
<RequiredDate>1997-08-28T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-08-04T00:00:00">
<ShipVia>2</ShipVia>
<Freight>18.53</Freight>
<ShipName>Great Lakes Food Market</ShipName>
<ShipAddress>2732 Baker Blvd.</ShipAddress>
<ShipCity>Eugene</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97403</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>GREAL</CustomerID>
<EmployeeID>6</EmployeeID>
<OrderDate>1997-09-04T00:00:00</OrderDate>
<RequiredDate>1997-10-02T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-09-10T00:00:00">
<ShipVia>1</ShipVia>
<Freight>57.15</Freight>
<ShipName>Great Lakes Food Market</ShipName>
<ShipAddress>2732 Baker Blvd.</ShipAddress>
<ShipCity>Eugene</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97403</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>GREAL</CustomerID>
<EmployeeID>3</EmployeeID>
<OrderDate>1997-09-25T00:00:00</OrderDate>
<RequiredDate>1997-10-23T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-09-30T00:00:00">
<ShipVia>3</ShipVia>
<Freight>76.13</Freight>
<ShipName>Great Lakes Food Market</ShipName>
<ShipAddress>2732 Baker Blvd.</ShipAddress>
<ShipCity>Eugene</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97403</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>GREAL</CustomerID>
<EmployeeID>4</EmployeeID>
<OrderDate>1998-01-06T00:00:00</OrderDate>
<RequiredDate>1998-02-03T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1998-02-04T00:00:00">
<ShipVia>2</ShipVia>
<Freight>719.78</Freight>
<ShipName>Great Lakes Food Market</ShipName>
<ShipAddress>2732 Baker Blvd.</ShipAddress>
<ShipCity>Eugene</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97403</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>GREAL</CustomerID>
<EmployeeID>3</EmployeeID>
<OrderDate>1998-03-09T00:00:00</OrderDate>
<RequiredDate>1998-04-06T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1998-03-18T00:00:00">
<ShipVia>2</ShipVia>
<Freight>33.68</Freight>
<Freight>33.68</Freight>
<ShipName>Great Lakes Food Market</ShipName>
<ShipAddress>2732 Baker Blvd.</ShipAddress>
<ShipCity>Eugene</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97403</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>GREAL</CustomerID>
<EmployeeID>3</EmployeeID>
<OrderDate>1998-04-07T00:00:00</OrderDate>
<RequiredDate>1998-05-05T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1998-04-15T00:00:00">
<ShipVia>2</ShipVia>
<Freight>25.19</Freight>
<ShipName>Great Lakes Food Market</ShipName>
<ShipAddress>2732 Baker Blvd.</ShipAddress>
<ShipCity>Eugene</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97403</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>GREAL</CustomerID>
<EmployeeID>4</EmployeeID>
<OrderDate>1998-04-22T00:00:00</OrderDate>
<RequiredDate>1998-05-20T00:00:00</RequiredDate>
<ShipInfo>
<ShipVia>3</ShipVia>
<Freight>18.84</Freight>
<ShipName>Great Lakes Food Market</ShipName>
<ShipAddress>2732 Baker Blvd.</ShipAddress>
<ShipCity>Eugene</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97403</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>GREAL</CustomerID>
<EmployeeID>4</EmployeeID>
<OrderDate>1998-04-30T00:00:00</OrderDate>
<RequiredDate>1998-06-11T00:00:00</RequiredDate>
<ShipInfo>
<ShipVia>3</ShipVia>
<Freight>14.01</Freight>
<ShipName>Great Lakes Food Market</ShipName>
<ShipAddress>2732 Baker Blvd.</ShipAddress>
<ShipCity>Eugene</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97403</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>HUNGC</CustomerID>
<EmployeeID>3</EmployeeID>
<OrderDate>1996-12-06T00:00:00</OrderDate>
<RequiredDate>1997-01-03T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1996-12-09T00:00:00">
<ShipVia>2</ShipVia>
<Freight>20.12</Freight>
<ShipName>Hungry Coyote Import Store</ShipName>
<ShipAddress>City Center Plaza 516 Main St.</ShipAddress>
<ShipCity>Elgin</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97827</ShipPostalCode>
<ShipPostalCode>97827</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>HUNGC</CustomerID>
<EmployeeID>1</EmployeeID>
<OrderDate>1996-12-25T00:00:00</OrderDate>
<RequiredDate>1997-01-22T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-01-03T00:00:00">
<ShipVia>3</ShipVia>
<Freight>30.34</Freight>
<ShipName>Hungry Coyote Import Store</ShipName>
<ShipAddress>City Center Plaza 516 Main St.</ShipAddress>
<ShipCity>Elgin</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97827</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>HUNGC</CustomerID>
<EmployeeID>3</EmployeeID>
<OrderDate>1997-01-15T00:00:00</OrderDate>
<RequiredDate>1997-02-12T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-01-24T00:00:00">
<ShipVia>1</ShipVia>
<Freight>0.2</Freight>
<ShipName>Hungry Coyote Import Store</ShipName>
<ShipAddress>City Center Plaza 516 Main St.</ShipAddress>
<ShipCity>Elgin</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97827</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>HUNGC</CustomerID>
<EmployeeID>4</EmployeeID>
<OrderDate>1997-07-16T00:00:00</OrderDate>
<RequiredDate>1997-08-13T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-07-21T00:00:00">
<ShipVia>1</ShipVia>
<Freight>45.13</Freight>
<ShipName>Hungry Coyote Import Store</ShipName>
<ShipAddress>City Center Plaza 516 Main St.</ShipAddress>
<ShipCity>Elgin</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97827</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>HUNGC</CustomerID>
<EmployeeID>8</EmployeeID>
<OrderDate>1997-09-08T00:00:00</OrderDate>
<RequiredDate>1997-10-06T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-10-15T00:00:00">
<ShipVia>1</ShipVia>
<Freight>111.29</Freight>
<ShipName>Hungry Coyote Import Store</ShipName>
<ShipAddress>City Center Plaza 516 Main St.</ShipAddress>
<ShipCity>Elgin</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97827</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>LAZYK</CustomerID>
<CustomerID>LAZYK</CustomerID>
<EmployeeID>1</EmployeeID>
<OrderDate>1997-03-21T00:00:00</OrderDate>
<RequiredDate>1997-04-18T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-04-10T00:00:00">
<ShipVia>3</ShipVia>
<Freight>7.48</Freight>
<ShipName>Lazy K Kountry Store</ShipName>
<ShipAddress>12 Orchestra Terrace</ShipAddress>
<ShipCity>Walla Walla</ShipCity>
<ShipRegion>WA</ShipRegion>
<ShipPostalCode>99362</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>LAZYK</CustomerID>
<EmployeeID>8</EmployeeID>
<OrderDate>1997-05-22T00:00:00</OrderDate>
<RequiredDate>1997-06-19T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-06-26T00:00:00">
<ShipVia>2</ShipVia>
<Freight>11.92</Freight>
<ShipName>Lazy K Kountry Store</ShipName>
<ShipAddress>12 Orchestra Terrace</ShipAddress>
<ShipCity>Walla Walla</ShipCity>
<ShipRegion>WA</ShipRegion>
<ShipPostalCode>99362</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>LETSS</CustomerID>
<EmployeeID>1</EmployeeID>
<OrderDate>1997-06-25T00:00:00</OrderDate>
<RequiredDate>1997-07-23T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-07-04T00:00:00">
<ShipVia>2</ShipVia>
<Freight>13.73</Freight>
<ShipName>Let's Stop N Shop</ShipName>
<ShipAddress>87 Polk St. Suite 5</ShipAddress>
<ShipCity>San Francisco</ShipCity>
<ShipRegion>CA</ShipRegion>
<ShipPostalCode>94117</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>LETSS</CustomerID>
<EmployeeID>8</EmployeeID>
<OrderDate>1997-10-27T00:00:00</OrderDate>
<RequiredDate>1997-11-24T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-11-05T00:00:00">
<ShipVia>2</ShipVia>
<Freight>51.44</Freight>
<ShipName>Let's Stop N Shop</ShipName>
<ShipAddress>87 Polk St. Suite 5</ShipAddress>
<ShipCity>San Francisco</ShipCity>
<ShipRegion>CA</ShipRegion>
<ShipPostalCode>94117</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>LETSS</CustomerID>
<EmployeeID>6</EmployeeID>
<OrderDate>1997-11-10T00:00:00</OrderDate>
<RequiredDate>1997-12-08T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-11-21T00:00:00">
<ShipVia>2</ShipVia>
<ShipVia>2</ShipVia>
<Freight>45.97</Freight>
<ShipName>Let's Stop N Shop</ShipName>
<ShipAddress>87 Polk St. Suite 5</ShipAddress>
<ShipCity>San Francisco</ShipCity>
<ShipRegion>CA</ShipRegion>
<ShipPostalCode>94117</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>LETSS</CustomerID>
<EmployeeID>4</EmployeeID>
<OrderDate>1998-02-12T00:00:00</OrderDate>
<RequiredDate>1998-03-12T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1998-02-13T00:00:00">
<ShipVia>2</ShipVia>
<Freight>90.97</Freight>
<ShipName>Let's Stop N Shop</ShipName>
<ShipAddress>87 Polk St. Suite 5</ShipAddress>
<ShipCity>San Francisco</ShipCity>
<ShipRegion>CA</ShipRegion>
<ShipPostalCode>94117</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
</Orders>
</Root>
Sample XSD File: Customers and Orders
9/3/2020 • 2 minutes to read • Edit Online
The following XSD file is used in various examples in the LINQ to XML documentation. This file contains a schema
definition for the Sample XML File: Customers and Orders (LINQ to XML). The schema uses the xs:key and
xs:keyref features of XSD to establish that the CustomerID attribute of the Customer element is a key, and to
establish a relationship between the CustomerID element in each Order element and the CustomerID attribute in
each Customer element.
For an example of writing LINQ queries that take advantage of this relationship using the Join clause, see How to
join two collections (LINQ to XML) (C#).
CustomersOrders.xsd
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name='Root'>
<xs:complexType>
<xs:sequence>
<xs:element name='Customers'>
<xs:complexType>
<xs:sequence>
<xs:element name='Customer' type='CustomerType' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name='Orders'>
<xs:complexType>
<xs:sequence>
<xs:element name='Order' type='OrderType' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:key name='CustomerIDKey'>
<xs:selector xpath='Customers/Customer'/>
<xs:field xpath='@CustomerID'/>
</xs:key>
<xs:keyref name='CustomerIDKeyRef' refer='CustomerIDKey'>
<xs:selector xpath='Orders/Order'/>
<xs:field xpath='CustomerID'/>
</xs:keyref>
</xs:element>
<xs:complexType name='CustomerType'>
<xs:sequence>
<xs:element name='CompanyName' type='xs:string'/>
<xs:element name='ContactName' type='xs:string'/>
<xs:element name='ContactTitle' type='xs:string'/>
<xs:element name='Phone' type='xs:string'/>
<xs:element name='Fax' minOccurs='0' type='xs:string'/>
<xs:element name='FullAddress' type='AddressType'/>
</xs:sequence>
<xs:attribute name='CustomerID' type='xs:token'/>
</xs:complexType>
<xs:complexType name='AddressType'>
<xs:sequence>
<xs:element name='Address' type='xs:string'/>
<xs:element name='City' type='xs:string'/>
<xs:element name='Region' type='xs:string'/>
<xs:element name='Region' type='xs:string'/>
<xs:element name='PostalCode' type='xs:string' />
<xs:element name='Country' type='xs:string'/>
</xs:sequence>
<xs:attribute name='CustomerID' type='xs:token'/>
</xs:complexType>
<xs:complexType name='OrderType'>
<xs:sequence>
<xs:element name='CustomerID' type='xs:token'/>
<xs:element name='EmployeeID' type='xs:token'/>
<xs:element name='OrderDate' type='xs:dateTime'/>
<xs:element name='RequiredDate' type='xs:dateTime'/>
<xs:element name='ShipInfo' type='ShipInfoType'/>
</xs:sequence>
</xs:complexType>
<xs:complexType name='ShipInfoType'>
<xs:sequence>
<xs:element name='ShipVia' type='xs:integer'/>
<xs:element name='Freight' type='xs:decimal'/>
<xs:element name='ShipName' type='xs:string'/>
<xs:element name='ShipAddress' type='xs:string'/>
<xs:element name='ShipCity' type='xs:string'/>
<xs:element name='ShipRegion' type='xs:string'/>
<xs:element name='ShipPostalCode' type='xs:string'/>
<xs:element name='ShipCountry' type='xs:string'/>
</xs:sequence>
<xs:attribute name='ShippedDate' type='xs:dateTime'/>
</xs:complexType>
</xs:schema>
Sample XML File: Customers and Orders in a
Namespace
9/3/2020 • 3 minutes to read • Edit Online
The following XML file is used in various examples in the LINQ to XML documentation. This file contains customers
and orders. The XML is in a namespace.
CustomersOrdersInNamespace.xml
<?xml version="1.0" encoding="utf-8"?>
<Root xmlns="http://www.adventure-works.com">
<Customers>
<Customer CustomerID="GREAL">
<CompanyName>Great Lakes Food Market</CompanyName>
<ContactName>Howard Snyder</ContactName>
<ContactTitle>Marketing Manager</ContactTitle>
<Phone>(503) 555-7555</Phone>
<FullAddress>
<Address>2732 Baker Blvd.</Address>
<City>Eugene</City>
<Region>OR</Region>
<PostalCode>97403</PostalCode>
<Country>USA</Country>
</FullAddress>
</Customer>
<Customer CustomerID="HUNGC">
<CompanyName>Hungry Coyote Import Store</CompanyName>
<ContactName>Yoshi Latimer</ContactName>
<ContactTitle>Sales Representative</ContactTitle>
<Phone>(503) 555-6874</Phone>
<Fax>(503) 555-2376</Fax>
<FullAddress>
<Address>City Center Plaza 516 Main St.</Address>
<City>Elgin</City>
<Region>OR</Region>
<PostalCode>97827</PostalCode>
<Country>USA</Country>
</FullAddress>
</Customer>
<Customer CustomerID="LAZYK">
<CompanyName>Lazy K Kountry Store</CompanyName>
<ContactName>John Steel</ContactName>
<ContactTitle>Marketing Manager</ContactTitle>
<Phone>(509) 555-7969</Phone>
<Fax>(509) 555-6221</Fax>
<FullAddress>
<Address>12 Orchestra Terrace</Address>
<City>Walla Walla</City>
<Region>WA</Region>
<PostalCode>99362</PostalCode>
<Country>USA</Country>
</FullAddress>
</Customer>
<Customer CustomerID="LETSS">
<CompanyName>Let's Stop N Shop</CompanyName>
<ContactName>Jaime Yorres</ContactName>
<ContactTitle>Owner</ContactTitle>
<Phone>(415) 555-5938</Phone>
<FullAddress>
<Address>87 Polk St. Suite 5</Address>
<Address>87 Polk St. Suite 5</Address>
<City>San Francisco</City>
<Region>CA</Region>
<PostalCode>94117</PostalCode>
<Country>USA</Country>
</FullAddress>
</Customer>
</Customers>
<Orders>
<Order>
<CustomerID>GREAL</CustomerID>
<EmployeeID>6</EmployeeID>
<OrderDate>1997-05-06T00:00:00</OrderDate>
<RequiredDate>1997-05-20T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-05-09T00:00:00">
<ShipVia>2</ShipVia>
<Freight>3.35</Freight>
<ShipName>Great Lakes Food Market</ShipName>
<ShipAddress>2732 Baker Blvd.</ShipAddress>
<ShipCity>Eugene</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97403</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>GREAL</CustomerID>
<EmployeeID>8</EmployeeID>
<OrderDate>1997-07-04T00:00:00</OrderDate>
<RequiredDate>1997-08-01T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-07-14T00:00:00">
<ShipVia>2</ShipVia>
<Freight>4.42</Freight>
<ShipName>Great Lakes Food Market</ShipName>
<ShipAddress>2732 Baker Blvd.</ShipAddress>
<ShipCity>Eugene</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97403</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>GREAL</CustomerID>
<EmployeeID>1</EmployeeID>
<OrderDate>1997-07-31T00:00:00</OrderDate>
<RequiredDate>1997-08-28T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-08-05T00:00:00">
<ShipVia>2</ShipVia>
<Freight>116.53</Freight>
<ShipName>Great Lakes Food Market</ShipName>
<ShipAddress>2732 Baker Blvd.</ShipAddress>
<ShipCity>Eugene</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97403</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>GREAL</CustomerID>
<EmployeeID>4</EmployeeID>
<OrderDate>1997-07-31T00:00:00</OrderDate>
<RequiredDate>1997-08-28T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-08-04T00:00:00">
<ShipVia>2</ShipVia>
<Freight>18.53</Freight>
<ShipName>Great Lakes Food Market</ShipName>
<ShipAddress>2732 Baker Blvd.</ShipAddress>
<ShipCity>Eugene</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97403</ShipPostalCode>
<ShipPostalCode>97403</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>GREAL</CustomerID>
<EmployeeID>6</EmployeeID>
<OrderDate>1997-09-04T00:00:00</OrderDate>
<RequiredDate>1997-10-02T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-09-10T00:00:00">
<ShipVia>1</ShipVia>
<Freight>57.15</Freight>
<ShipName>Great Lakes Food Market</ShipName>
<ShipAddress>2732 Baker Blvd.</ShipAddress>
<ShipCity>Eugene</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97403</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>GREAL</CustomerID>
<EmployeeID>3</EmployeeID>
<OrderDate>1997-09-25T00:00:00</OrderDate>
<RequiredDate>1997-10-23T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-09-30T00:00:00">
<ShipVia>3</ShipVia>
<Freight>76.13</Freight>
<ShipName>Great Lakes Food Market</ShipName>
<ShipAddress>2732 Baker Blvd.</ShipAddress>
<ShipCity>Eugene</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97403</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>GREAL</CustomerID>
<EmployeeID>4</EmployeeID>
<OrderDate>1998-01-06T00:00:00</OrderDate>
<RequiredDate>1998-02-03T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1998-02-04T00:00:00">
<ShipVia>2</ShipVia>
<Freight>719.78</Freight>
<ShipName>Great Lakes Food Market</ShipName>
<ShipAddress>2732 Baker Blvd.</ShipAddress>
<ShipCity>Eugene</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97403</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>GREAL</CustomerID>
<EmployeeID>3</EmployeeID>
<OrderDate>1998-03-09T00:00:00</OrderDate>
<RequiredDate>1998-04-06T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1998-03-18T00:00:00">
<ShipVia>2</ShipVia>
<Freight>33.68</Freight>
<ShipName>Great Lakes Food Market</ShipName>
<ShipAddress>2732 Baker Blvd.</ShipAddress>
<ShipCity>Eugene</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97403</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>GREAL</CustomerID>
<CustomerID>GREAL</CustomerID>
<EmployeeID>3</EmployeeID>
<OrderDate>1998-04-07T00:00:00</OrderDate>
<RequiredDate>1998-05-05T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1998-04-15T00:00:00">
<ShipVia>2</ShipVia>
<Freight>25.19</Freight>
<ShipName>Great Lakes Food Market</ShipName>
<ShipAddress>2732 Baker Blvd.</ShipAddress>
<ShipCity>Eugene</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97403</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>GREAL</CustomerID>
<EmployeeID>4</EmployeeID>
<OrderDate>1998-04-22T00:00:00</OrderDate>
<RequiredDate>1998-05-20T00:00:00</RequiredDate>
<ShipInfo>
<ShipVia>3</ShipVia>
<Freight>18.84</Freight>
<ShipName>Great Lakes Food Market</ShipName>
<ShipAddress>2732 Baker Blvd.</ShipAddress>
<ShipCity>Eugene</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97403</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>GREAL</CustomerID>
<EmployeeID>4</EmployeeID>
<OrderDate>1998-04-30T00:00:00</OrderDate>
<RequiredDate>1998-06-11T00:00:00</RequiredDate>
<ShipInfo>
<ShipVia>3</ShipVia>
<Freight>14.01</Freight>
<ShipName>Great Lakes Food Market</ShipName>
<ShipAddress>2732 Baker Blvd.</ShipAddress>
<ShipCity>Eugene</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97403</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>HUNGC</CustomerID>
<EmployeeID>3</EmployeeID>
<OrderDate>1996-12-06T00:00:00</OrderDate>
<RequiredDate>1997-01-03T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1996-12-09T00:00:00">
<ShipVia>2</ShipVia>
<Freight>20.12</Freight>
<ShipName>Hungry Coyote Import Store</ShipName>
<ShipAddress>City Center Plaza 516 Main St.</ShipAddress>
<ShipCity>Elgin</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97827</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>HUNGC</CustomerID>
<EmployeeID>1</EmployeeID>
<OrderDate>1996-12-25T00:00:00</OrderDate>
<RequiredDate>1997-01-22T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-01-03T00:00:00">
<ShipVia>3</ShipVia>
<Freight>30.34</Freight>
<ShipName>Hungry Coyote Import Store</ShipName>
<ShipAddress>City Center Plaza 516 Main St.</ShipAddress>
<ShipCity>Elgin</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97827</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>HUNGC</CustomerID>
<EmployeeID>3</EmployeeID>
<OrderDate>1997-01-15T00:00:00</OrderDate>
<RequiredDate>1997-02-12T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-01-24T00:00:00">
<ShipVia>1</ShipVia>
<Freight>0.2</Freight>
<ShipName>Hungry Coyote Import Store</ShipName>
<ShipAddress>City Center Plaza 516 Main St.</ShipAddress>
<ShipCity>Elgin</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97827</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>HUNGC</CustomerID>
<EmployeeID>4</EmployeeID>
<OrderDate>1997-07-16T00:00:00</OrderDate>
<RequiredDate>1997-08-13T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-07-21T00:00:00">
<ShipVia>1</ShipVia>
<Freight>45.13</Freight>
<ShipName>Hungry Coyote Import Store</ShipName>
<ShipAddress>City Center Plaza 516 Main St.</ShipAddress>
<ShipCity>Elgin</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97827</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>HUNGC</CustomerID>
<EmployeeID>8</EmployeeID>
<OrderDate>1997-09-08T00:00:00</OrderDate>
<RequiredDate>1997-10-06T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-10-15T00:00:00">
<ShipVia>1</ShipVia>
<Freight>111.29</Freight>
<ShipName>Hungry Coyote Import Store</ShipName>
<ShipAddress>City Center Plaza 516 Main St.</ShipAddress>
<ShipCity>Elgin</ShipCity>
<ShipRegion>OR</ShipRegion>
<ShipPostalCode>97827</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>LAZYK</CustomerID>
<EmployeeID>1</EmployeeID>
<OrderDate>1997-03-21T00:00:00</OrderDate>
<RequiredDate>1997-04-18T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-04-10T00:00:00">
<ShipVia>3</ShipVia>
<Freight>7.48</Freight>
<ShipName>Lazy K Kountry Store</ShipName>
<ShipAddress>12 Orchestra Terrace</ShipAddress>
<ShipCity>Walla Walla</ShipCity>
<ShipRegion>WA</ShipRegion>
<ShipPostalCode>99362</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>LAZYK</CustomerID>
<EmployeeID>8</EmployeeID>
<OrderDate>1997-05-22T00:00:00</OrderDate>
<RequiredDate>1997-06-19T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-06-26T00:00:00">
<ShipVia>2</ShipVia>
<Freight>11.92</Freight>
<ShipName>Lazy K Kountry Store</ShipName>
<ShipAddress>12 Orchestra Terrace</ShipAddress>
<ShipCity>Walla Walla</ShipCity>
<ShipRegion>WA</ShipRegion>
<ShipPostalCode>99362</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>LETSS</CustomerID>
<EmployeeID>1</EmployeeID>
<OrderDate>1997-06-25T00:00:00</OrderDate>
<RequiredDate>1997-07-23T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-07-04T00:00:00">
<ShipVia>2</ShipVia>
<Freight>13.73</Freight>
<ShipName>Let's Stop N Shop</ShipName>
<ShipAddress>87 Polk St. Suite 5</ShipAddress>
<ShipCity>San Francisco</ShipCity>
<ShipRegion>CA</ShipRegion>
<ShipPostalCode>94117</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>LETSS</CustomerID>
<EmployeeID>8</EmployeeID>
<OrderDate>1997-10-27T00:00:00</OrderDate>
<RequiredDate>1997-11-24T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-11-05T00:00:00">
<ShipVia>2</ShipVia>
<Freight>51.44</Freight>
<ShipName>Let's Stop N Shop</ShipName>
<ShipAddress>87 Polk St. Suite 5</ShipAddress>
<ShipCity>San Francisco</ShipCity>
<ShipRegion>CA</ShipRegion>
<ShipPostalCode>94117</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
<Order>
<CustomerID>LETSS</CustomerID>
<EmployeeID>6</EmployeeID>
<OrderDate>1997-11-10T00:00:00</OrderDate>
<RequiredDate>1997-12-08T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1997-11-21T00:00:00">
<ShipVia>2</ShipVia>
<Freight>45.97</Freight>
<ShipName>Let's Stop N Shop</ShipName>
<ShipAddress>87 Polk St. Suite 5</ShipAddress>
<ShipCity>San Francisco</ShipCity>
<ShipRegion>CA</ShipRegion>
<ShipPostalCode>94117</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
</Order>
<Order>
<CustomerID>LETSS</CustomerID>
<EmployeeID>4</EmployeeID>
<OrderDate>1998-02-12T00:00:00</OrderDate>
<RequiredDate>1998-03-12T00:00:00</RequiredDate>
<ShipInfo ShippedDate="1998-02-13T00:00:00">
<ShipVia>2</ShipVia>
<Freight>90.97</Freight>
<ShipName>Let's Stop N Shop</ShipName>
<ShipAddress>87 Polk St. Suite 5</ShipAddress>
<ShipCity>San Francisco</ShipCity>
<ShipRegion>CA</ShipRegion>
<ShipPostalCode>94117</ShipPostalCode>
<ShipCountry>USA</ShipCountry>
</ShipInfo>
</Order>
</Orders>
</Root>
Sample XML File: Numerical Data (LINQ to XML)
9/3/2020 • 2 minutes to read • Edit Online
The following XML file is used in various examples in the LINQ to XML documentation. This file contains numerical
data for summing, averaging, and grouping.
Data.xml
<Root>
<TaxRate>7.25</TaxRate>
<Data>
<Category>A</Category>
<Quantity>3</Quantity>
<Price>24.50</Price>
</Data>
<Data>
<Category>B</Category>
<Quantity>1</Quantity>
<Price>89.99</Price>
</Data>
<Data>
<Category>A</Category>
<Quantity>5</Quantity>
<Price>4.95</Price>
</Data>
<Data>
<Category>A</Category>
<Quantity>3</Quantity>
<Price>66.00</Price>
</Data>
<Data>
<Category>B</Category>
<Quantity>10</Quantity>
<Price>.99</Price>
</Data>
<Data>
<Category>A</Category>
<Quantity>15</Quantity>
<Price>29.00</Price>
</Data>
<Data>
<Category>B</Category>
<Quantity>8</Quantity>
<Price>6.99</Price>
</Data>
</Root>
Sample XML File: Numerical Data in a Namespace
9/3/2020 • 2 minutes to read • Edit Online
The following XML file is used in various examples in the LINQ to XML documentation. This file contains numerical
data for summing, averaging, and grouping. The XML is in a namespace.
Data
<Root xmlns='http://www.adatum.com'>
<TaxRate>7.25</TaxRate>
<Data>
<Category>A</Category>
<Quantity>3</Quantity>
<Price>24.50</Price>
</Data>
<Data>
<Category>B</Category>
<Quantity>1</Quantity>
<Price>89.99</Price>
</Data>
<Data>
<Category>A</Category>
<Quantity>5</Quantity>
<Price>4.95</Price>
</Data>
<Data>
<Category>A</Category>
<Quantity>3</Quantity>
<Price>66.00</Price>
</Data>
<Data>
<Category>B</Category>
<Quantity>10</Quantity>
<Price>.99</Price>
</Data>
<Data>
<Category>A</Category>
<Quantity>15</Quantity>
<Price>29.00</Price>
</Data>
<Data>
<Category>B</Category>
<Quantity>8</Quantity>
<Price>6.99</Price>
</Data>
</Root>
Sample XML File: Books (LINQ to XML)
9/3/2020 • 2 minutes to read • Edit Online
The following XML file is used in various examples in the LINQ to XML documentation. The file contains
information about books.
books.xml
<?xml version="1.0"?>
<Catalog>
<Book id="bk101">
<Author>Garghentini, Davide</Author>
<Title>XML Developer's Guide</Title>
<Genre>Computer</Genre>
<Price>44.95</Price>
<PublishDate>2000-10-01</PublishDate>
<Description>An in-depth look at creating applications
with XML.</Description>
</Book>
<Book id="bk102">
<Author>Garcia, Debra</Author>
<Title>Midnight Rain</Title>
<Genre>Fantasy</Genre>
<Price>5.95</Price>
<PublishDate>2000-12-16</PublishDate>
<Description>A former architect battles corporate zombies,
an evil sorceress, and her own childhood to become queen
of the world.</Description>
</Book>
</Catalog>
Sample XML File: Consolidated Purchase Orders
9/3/2020 • 2 minutes to read • Edit Online
The following XML file is used in various examples in the LINQ to XML documentation. This file is a set of purchase
orders with different shapes from multiple companies. Purchase orders from each company are in separate
namespaces.
ConsolidatedPurchaseOrders.xml
<?xml version="1.0"?>
<PurchaseOrders xmlns="www.contoso.com">
<PurchaseOrder
PurchaseOrderNumber="99503"
OrderDate="1999-10-20">
<Address Type="Shipping">
<Name>Ellen Adams</Name>
<Street>123 Maple Street</Street>
<City>Mill Valley</City>
<State>CA</State>
<Zip>10999</Zip>
<Country>USA</Country>
</Address>
<Address Type="Billing">
<Name>Tai Yee</Name>
<Street>8 Oak Avenue</Street>
<City>Old Town</City>
<State>PA</State>
<Zip>95819</Zip>
<Country>USA</Country>
</Address>
<DeliveryNotes>Please leave packages in shed by driveway.</DeliveryNotes>
<Items>
<Item PartNumber="872-AA">
<ProductName>Lawnmower</ProductName>
<Quantity>1</Quantity>
<USPrice>148.95</USPrice>
<Comment>Confirm this is electric</Comment>
</Item>
<Item PartNumber="926-AA">
<ProductName>Baby Monitor</ProductName>
<Quantity>2</Quantity>
<USPrice>39.98</USPrice>
<ShipDate>1999-05-21</ShipDate>
</Item>
</Items>
</PurchaseOrder>
<PurchaseOrder PurchaseOrderNumber="99505" OrderDate="1999-10-22">
<Address Type="Shipping">
<Name>Cristian Osorio</Name>
<Street>456 Main Street</Street>
<City>Buffalo</City>
<State>NY</State>
<Zip>98112</Zip>
<Country>USA</Country>
</Address>
<Address Type="Billing">
<Name>Cristian Osorio</Name>
<Street>456 Main Street</Street>
<City>Buffalo</City>
<State>NY</State>
<Zip>98112</Zip>
<Zip>98112</Zip>
<Country>USA</Country>
</Address>
<DeliveryNotes>Please notify by email before shipping.</DeliveryNotes>
<Items>
<Item PartNumber="456-NM">
<ProductName>Power Supply</ProductName>
<Quantity>1</Quantity>
<USPrice>45.99</USPrice>
</Item>
</Items>
</PurchaseOrder>
<PurchaseOrder PurchaseOrderNumber="99504" OrderDate="1999-10-22">
<Address Type="Shipping">
<Name>Jessica Arnold</Name>
<Street>4055 Madison Ave</Street>
<City>Seattle</City>
<State>WA</State>
<Zip>98112</Zip>
<Country>USA</Country>
</Address>
<Address Type="Billing">
<Name>Jessica Arnold</Name>
<Street>4055 Madison Ave</Street>
<City>Buffalo</City>
<State>NY</State>
<Zip>98112</Zip>
<Country>USA</Country>
</Address>
<DeliveryNotes>Please do not deliver on Saturday.</DeliveryNotes>
<Items>
<Item PartNumber="898-AZ">
<ProductName>Computer Keyboard</ProductName>
<Quantity>1</Quantity>
<USPrice>29.99</USPrice>
</Item>
<Item PartNumber="898-AM">
<ProductName>Wireless Mouse</ProductName>
<Quantity>1</Quantity>
<USPrice>14.99</USPrice>
</Item>
</Items>
</PurchaseOrder>
<aw:PurchaseOrder
PONumber="11223"
Date="2000-01-15"
xmlns:aw="http://www.adventure-works.com">
<aw:ShippingAddress>
<aw:Name>Chris Preston</aw:Name>
<aw:Street>123 Main St.</aw:Street>
<aw:City>Seattle</aw:City>
<aw:State>WA</aw:State>
<aw:Zip>98113</aw:Zip>
<aw:Country>USA</aw:Country>
</aw:ShippingAddress>
<aw:BillingAddress>
<aw:Name>Chris Preston</aw:Name>
<aw:Street>123 Main St.</aw:Street>
<aw:City>Seattle</aw:City>
<aw:State>WA</aw:State>
<aw:Zip>98113</aw:Zip>
<aw:Country>USA</aw:Country>
</aw:BillingAddress>
<aw:DeliveryInstructions>Ship only complete order.</aw:DeliveryInstructions>
<aw:Item PartNum="LIT-01">
<aw:ProductID>Litware Networking Card</aw:ProductID>
<aw:Qty>1</aw:Qty>
<aw:Price>20.99</aw:Price>
</aw:Item>
<aw:Item PartNum="LIT-25">
<aw:Item PartNum="LIT-25">
<aw:ProductID>Litware 17in LCD Monitor</aw:ProductID>
<aw:Qty>1</aw:Qty>
<aw:Price>199.99</aw:Price>
</aw:Item>
</aw:PurchaseOrder>
</PurchaseOrders>
Reference (LINQ to XML)
9/3/2020 • 2 minutes to read • Edit Online
In This Section
For reference documentation for the LINQ to XML classes, see System.Xml.Linq.
For reference documentation for the extension methods that help you validate XML trees against an XSD file, see
System.Xml.Schema.Extensions.
For reference documentation for the extension methods that enable you to evaluate XPath queries on an XML tree,
see System.Xml.XPath.Extensions.
See also
LINQ to XML (C#)
LINQ to ADO.NET (Portal Page)
9/3/2020 • 2 minutes to read • Edit Online
LINQ to ADO.NET enables you to query over any enumerable object in ADO.NET by using the Language-Integrated
Query (LINQ) programming model.
NOTE
The LINQ to ADO.NET documentation is located in the ADO.NET section of the .NET Framework SDK: LINQ and ADO.NET.
There are three separate ADO.NET Language-Integrated Query (LINQ) technologies: LINQ to DataSet, LINQ to SQL,
and LINQ to Entities. LINQ to DataSet provides richer, optimized querying over the DataSet, LINQ to SQL enables
you to directly query SQL Server database schemas, and LINQ to Entities allows you to query an Entity Data Model.
LINQ to DataSet
The DataSet is one of the most widely used components in ADO.NET, and is a key element of the disconnected
programming model that ADO.NET is built on. Despite this prominence, however, the DataSet has limited query
capabilities.
LINQ to DataSet enables you to build richer query capabilities into DataSet by using the same query functionality
that is available for many other data sources.
For more information, see LINQ to DataSet.
LINQ to SQL
LINQ to SQL provides a run-time infrastructure for managing relational data as objects. In LINQ to SQL, the data
model of a relational database is mapped to an object model expressed in the programming language of the
developer. When you execute the application, LINQ to SQL translates language-integrated queries in the object
model into SQL and sends them to the database for execution. When the database returns the results, LINQ to SQL
translates them back into objects that you can manipulate.
LINQ to SQL includes support for stored procedures and user-defined functions in the database, and for inheritance
in the object model.
For more information, see LINQ to SQL.
LINQ to Entities
Through the Entity Data Model, relational data is exposed as objects in the .NET environment. This makes the object
layer an ideal target for LINQ support, allowing developers to formulate queries against the database from the
language used to build the business logic. This capability is known as LINQ to Entities. See LINQ to Entities for more
information.
See also
LINQ and ADO.NET
Language-Integrated Query (LINQ) (C#)
Enabling a Data Source for LINQ Querying
9/3/2020 • 3 minutes to read • Edit Online
There are various ways to extend LINQ to enable any data source to be queried in the LINQ pattern. The data source
might be a data structure, a Web service, a file system, or a database, to name some. The LINQ pattern makes it
easy for clients to query a data source for which LINQ querying is enabled, because the syntax and pattern of the
query does not change. The ways in which LINQ can be extended to these data sources include the following:
Implementing the IEnumerable<T> interface in a type to enable LINQ to Objects querying of that type.
Creating standard query operator methods such as Where and Select that extend a type, to enable custom
LINQ querying of that type.
Creating a provider for your data source that implements the IQueryable<T> interface. A provider that
implements this interface receives LINQ queries in the form of expression trees, which it can execute in a
custom way, for example remotely.
Creating a provider for your data source that takes advantage of an existing LINQ technology. Such a
provider would enable not only querying, but also insert, update, and delete operations and mapping for
user-defined types.
This topic discusses these options.
See also
IQueryable<T>
IEnumerable<T>
Enumerable
Standard Query Operators Overview (C#)
LINQ to Objects (C#)
Visual Studio IDE and Tools Support for LINQ (C#)
9/3/2020 • 2 minutes to read • Edit Online
The Visual Studio integrated development environment (IDE) provides the following features that support LINQ
application development:
See also
Language-Integrated Query (LINQ) (C#)
Object-Oriented programming (C#)
9/3/2020 • 9 minutes to read • Edit Online
C# provides full support for object-oriented programming including abstraction, encapsulation, inheritance, and
polymorphism.
Abstraction means hiding the unnecessary details from type consumers.
Encapsulation means that a group of related properties, methods, and other members are treated as a single
unit or object.
Inheritance describes the ability to create new classes based on an existing class.
Polymorphism means that you can have multiple classes that can be used interchangeably, even though each
class implements the same properties or methods in different ways.
class SampleClass
{
}
C# also provides types called structures that are useful when you don't need support for inheritance or
polymorphism. For more information, see Choosing between class and struct.
To define a structure:
struct SampleStruct
{
}
For more information, see the articles on the class and struct keywords.
Class members
Each class can have different class members that include properties that describe class data, methods that define
class behavior, and events that provide communication between different classes and objects.
Properties and fields
Fields and properties represent information that an object contains. Fields are like variables because they can be
read or set directly, subject to applicable access modifiers.
To define a field that can be accessed from within instances of the class:
class SampleClass
{
public int SampleProperty { get; set; }
}
If you need to perform some additional operations for reading and writing the property value, define a field for
storing the property value and provide the basic logic for storing and retrieving it:
class SampleClass
{
private int _sample;
public int Sample
{
// Return the value stored in a field.
get => _sample;
// Store the value in the field.
set => _sample = value;
}
}
Most properties have methods or procedures to both set and get the property value. However, you can create
read-only or write-only properties to restrict them from being modified or read. In C#, you can omit the get or
set property method. However, auto-implemented properties cannot be write-only. Read-only auto-implemented
properties can be set in constructors of the containing class.
For more information, see:
get
set
Methods
A method is an action that an object can perform.
To define a method of a class:
class SampleClass
{
public int SampleMethod(string sampleParam)
{
// Insert code here
}
}
A class can have several implementations, or overloads, of the same method that differ in the number of
parameters or parameter types.
To overload a method:
class Container
{
class Nested
{
// Add code here.
}
}
To create an instance of the nested class, use the name of the container class followed by the dot and then followed
by the name of the nested class:
Container.Nested nestedInstance = new Container.Nested()
public The type or member can be accessed by any other code in the
same assembly or another assembly that references it.
internal The type or member can be accessed by any code in the same
assembly, but not from another assembly.
protected internal The type or member can be accessed by any code in the same
assembly, or by any derived class in another assembly.
private protected The type or member can be accessed by code in the same
class or in a derived class within the base class assembly.
After instantiating a class, you can assign values to the instance's properties and fields and invoke class methods.
To assign values to properties during the class instantiation process, use object initializers:
To access the static member, use the name of the class without creating an object of this class:
Console.WriteLine(SampleClass.SampleString);
Static classes in C# have static members only and cannot be instantiated. Static members also cannot access non-
static properties, fields or methods
For more information, see: static.
Anonymous types
Anonymous types enable you to create objects without writing a class definition for the data type. Instead, the
compiler generates a class for you. The class has no usable name and contains the properties you specify in
declaring the object.
To create an instance of an anonymous type:
Inheritance
Inheritance enables you to create a new class that reuses, extends, and modifies the behavior that is defined in
another class. The class whose members are inherited is called the base class, and the class that inherits those
members is called the derived class. However, all classes in C# implicitly inherit from the Object class that supports
.NET class hierarchy and provides low-level services to all classes.
NOTE
C# doesn't support multiple inheritance. That is, you can specify only one base class for a derived class.
class DerivedClass:BaseClass { }
By default all classes can be inherited. However, you can specify whether a class must not be used as a base class,
or create a class that can be used as a base class only.
To specify that a class cannot be used as a base class:
To specify that a class can be used as a base class only and cannot be instantiated:
Interfaces
Interfaces, like classes, define a set of properties, methods, and events. But unlike classes, interfaces do not provide
implementation. They are implemented by classes, and defined as separate entities from classes. An interface
represents a contract, in that a class that implements an interface must implement every aspect of that interface
exactly as it is defined.
To define an interface:
interface ISampleInterface
{
void DoSomething();
}
For more information, see the programming guide article on Interfaces and the language reference article on the
interface keyword.
Generics
Classes, structures, interfaces, and methods in .NET can include type parameters that define types of objects that
they can store or use. The most common example of generics is a collection, where you can specify the type of
objects to be stored in a collection.
To define a generic class:
Delegates
A delegate is a type that defines a method signature, and can provide a reference to any method with a compatible
signature. You can invoke (or call) the method through the delegate. Delegates are used to pass methods as
arguments to other methods.
NOTE
Event handlers are nothing more than methods that are invoked through delegates. For more information about using
delegates in event handling, see Events.
To create a delegate:
To create a reference to a method that matches the signature specified by the delegate:
class SampleClass
{
// Method that matches the SampleDelegate signature.
public static void SampleMethod(string message)
{
// Add code here.
}
For more information, see the programming guide article on Delegates and the language reference article on the
delegate keyword.
See also
C# Programming Guide
Reflection (C#)
9/3/2020 • 2 minutes to read • Edit Online
Reflection provides objects (of type Type) that describe assemblies, modules, and types. You can use reflection to
dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing
object and invoke its methods or access its fields and properties. If you are using attributes in your code,
reflection enables you to access them. For more information, see Attributes.
Here's a simple example of reflection using the GetType() method - inherited by all types from the Object base
class - to obtain the type of a variable:
NOTE
Make sure you add using System; and using System.Reflection; at the top of your .cs file.
NOTE
The C# keywords protected and internal have no meaning in IL and are not used in the reflection APIs. The
corresponding terms in IL are Family and Assembly. To identify an internal method using reflection, use the IsAssembly
property. To identify a protected internal method, use the IsFamilyOrAssembly.
Reflection overview
Reflection is useful in the following situations:
When you have to access attributes in your program's metadata. For more information, see Retrieving
Information Stored in Attributes.
For examining and instantiating types in an assembly.
For building new types at runtime. Use classes in System.Reflection.Emit.
For performing late binding, accessing methods on types created at run time. See the topic Dynamically
Loading and Using Types.
Related sections
For more information:
Reflection
Viewing Type Information
Reflection and Generic Types
System.Reflection.Emit
Retrieving Information Stored in Attributes
See also
C# Programming Guide
Assemblies in .NET
Serialization (C#)
9/3/2020 • 4 minutes to read • Edit Online
Serialization is the process of converting an object into a stream of bytes to store the object or transmit it to
memory, a database, or a file. Its main purpose is to save the state of an object in order to be able to recreate it
when needed. The reverse process is called deserialization.
The object is serialized to a stream that carries the data. The stream may also have information about the object's
type, such as its version, culture, and assembly name. From that stream, the object can be stored in a database, a
file, or memory.
Uses for serialization
Serialization allows the developer to save the state of an object and re-create it as needed, providing storage of
objects as well as data exchange. Through serialization, a developer can perform actions such as:
Sending the object to a remote application by using a web service
Passing an object from one domain to another
Passing an object through a firewall as a JSON or XML string
Maintaining security or user-specific information across applications
JSON serialization
The System.Text.Json namespace contains classes for JavaScript Object Notation (JSON) serialization and
deserialization. JSON is an open standard that is commonly used for sharing data across the web.
JSON serialization serializes the public properties of an object into a string, byte array, or stream that conforms to
the RFC 8259 JSON specification. To control the way JsonSerializer serializes or deserializes an instance of the
class:
Use a JsonSerializerOptions object
Apply attributes from the System.Text.Json.Serialization namespace to classes or properties
Implement custom converters
WARNING
Binary serialization can be dangerous. For more information, see BinaryFormatter security guide.
XML serialization serializes the public fields and properties of an object, or the parameters and return values of
methods, into an XML stream that conforms to a specific XML Schema definition language (XSD) document. XML
serialization results in strongly typed classes with public properties and fields that are converted to XML.
System.Xml.Serialization contains classes for serializing and deserializing XML. You apply attributes to classes and
class members to control the way the XmlSerializer serializes or deserializes an instance of the class.
Making an object serializable
For binary or XML serialization, you need:
The object to be serialized
A stream to contain the serialized object
A System.Runtime.Serialization.Formatter instance
Apply the SerializableAttribute attribute to a type to indicate that instances of the type can be serialized. An
exception is thrown if you attempt to serialize but the type doesn't have the SerializableAttribute attribute.
To prevent a field from being serialized, apply the NonSerializedAttribute attribute. If a field of a serializable type
contains a pointer, a handle, or some other data structure that is specific to a particular environment, and the field
cannot be meaningfully reconstituted in a different environment, then you may want to make it nonserializable.
If a serialized class contains references to objects of other classes that are marked SerializableAttribute, those
objects will also be serialized.
Basic and custom serialization
Binary and XML serialization can be performed in two ways, basic and custom.
Basic serialization uses .NET to automatically serialize the object. The only requirement is that the class has the
SerializableAttribute attribute applied. The NonSerializedAttribute can be used to keep specific fields from being
serialized.
When you use basic serialization, the versioning of objects may create problems. You would use custom
serialization when versioning issues are important. Basic serialization is the easiest way to perform serialization,
but it does not provide much control over the process.
In custom serialization, you can specify exactly which objects will be serialized and how it will be done. The class
must be marked SerializableAttribute and implement the ISerializable interface. If you want your object to be
deserialized in a custom manner as well, use a custom constructor.
Designer serialization
Designer serialization is a special form of serialization that involves the kind of object persistence associated with
development tools. Designer serialization is the process of converting an object graph into a source file that can
later be used to recover the object graph. A source file can contain code, markup, or even SQL table information.
This example writes the object from a class to an XML file using the XmlSerializer class.
Example
public class XMLWrite
{
writer.Serialize(file, overview);
file.Close();
}
}
Robust Programming
The following conditions may cause an exception:
The class being serialized does not have a public, parameterless constructor.
The file exists and is read-only (IOException).
The path is too long (PathTooLongException).
The disk is full (IOException).
.NET Security
This example creates a new file, if the file does not already exist. If an application needs to create a file, that
application needs Create access for the folder. If the file already exists, the application needs only Write access, a
lesser privilege. Where possible, it is more secure to create the file during deployment, and only grant Read access
to a single file, rather than Create access for a folder.
See also
StreamWriter
How to read object data from an XML file (C#)
Serialization (C#)
How to read object data from an XML file (C#)
9/3/2020 • 2 minutes to read • Edit Online
This example reads object data that was previously written to an XML file using the XmlSerializer class.
Example
public class Book
{
public String title;
}
Console.WriteLine(overview.title);
Robust Programming
The following conditions may cause an exception:
The class being serialized does not have a public, parameterless constructor.
The data in the file does not represent data from the class to be deserialized.
The file does not exist (IOException).
.NET Security
Always verify inputs, and never deserialize data from an untrusted source. The re-created object runs on a local
computer with the permissions of the code that deserialized it. Verify all inputs before using the data in your
application.
See also
StreamWriter
How to write object data to an XML file (C#)
Serialization (C#)
C# Programming Guide
Walkthrough: persisting an object using C#
9/3/2020 • 4 minutes to read • Edit Online
You can use serialization to persist an object's data between instances, which enables you to store values and
retrieve them the next time that the object is instantiated.
In this walkthrough, you will create a basic Loan object and persist its data to a file. You will then retrieve the data
from the file when you re-create the object.
IMPORTANT
This example creates a new file if the file does not already exist. If an application must create a file, that application must have
Create permission for the folder. Permissions are set by using access control lists. If the file already exists, the application
needs only Write permission, a lesser permission. Where possible, it's more secure to create the file during deployment and
only grant Read permissions to a single file (instead of Create permissions for a folder). Also, it's more secure to write data
to user folders than to the root folder or the Program Files folder.
IMPORTANT
This example stores data in a binary format file. These formats should not be used for sensitive data, such as passwords or
credit-card information.
Prerequisites
To build and run, install the .NET Core SDK.
Install your favorite code editor, if you haven't already.
TIP
Need to install a code editor? Try Visual Studio!
[field:NonSerialized()]
public DateTime TimeLastLoaded { get; set; }
[field: NonSerialized()]
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
You will also have to create an application that uses the Loan class.
Add an event handler for the PropertyChanged event, and a few lines to modify the Loan object and display the
changes. You can see the additions in the following code:
At this point, you can run the code, and see the current output:
New customer value: Henry Clay
7.5
7.1
Running this application repeatedly always writes the same values. A new Loan object is created every time you
run the program. In the real world, interest rates change periodically, but not necessarily every time that the
application is run. Serialization code means you preserve the most recent interest rate between instances of the
application. In the next step, you will do just that by adding serialization to the Loan class.
[Serializable()]
The SerializableAttribute tells the compiler that everything in the class can be persisted to a file. Because the
PropertyChanged event does not represent part of the object graph that should be stored, it should not be
serialized. Doing so would serialize all objects that are attached to that event. You can add the
NonSerializedAttribute to the field declaration for the PropertyChanged event handler.
[field: NonSerialized()]
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
Beginning with C# 7.3, you can attach attributes to the backing field of an auto-implemented property using the
field target value. The following code adds a TimeLastLoaded property and marks it as not serializable:
[field:NonSerialized()]
public DateTime TimeLastLoaded { get; set; }
The next step is to add the serialization code to the LoanApp application. In order to serialize the class and write it
to a file, you use the System.IO and System.Runtime.Serialization.Formatters.Binary namespaces. To avoid typing
the fully qualified names, you can add references to the necessary namespaces as shown in the following code:
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
The next step is to add code to deserialize the object from the file when the object is created. Add a constant to the
class for the serialized data's file name as shown in the following code:
Next, add the following code after the line that creates the TestLoan object:
if (File.Exists(FileName))
{
Console.WriteLine("Reading saved file");
Stream openFileStream = File.OpenRead(FileName);
BinaryFormatter deserializer = new BinaryFormatter();
TestLoan = (Loan)deserializer.Deserialize(openFileStream);
TestLoan.TimeLastLoaded = DateTime.Now;
openFileStream.Close();
}
You first must check that the file exists. If it exists, create a Stream class to read the binary file and a
BinaryFormatter class to translate the file. You also need to convert from the stream type to the Loan object type.
Next you must add code to serialize the class to a file. Add the following code after the existing code in the Main
method:
At this point, you can again build and run the application. The first time it runs, notice that the interest rates starts
at 7.5, and then changes to 7.1. Close the application and then run it again. Now, the application prints the message
that it has read the saved file, and the interest rate is 7.1 even before the code that changes it.
See also
Serialization (C#)
C# Programming Guide
Statements, Expressions, and Operators (C#
Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
The C# code that comprises an application consists of statements made up of keywords, expressions and
operators. This section contains information regarding these fundamental elements of a C# program.
For more information, see:
Statements
Operators and expressions
Expression-bodied members
Anonymous Functions
Equality Comparisons
C# Language Specification
For more information, see the C# Language Specification. The language specification is the definitive source for C#
syntax and usage.
See also
C# Programming Guide
Casting and Type Conversions
Statements (C# Programming Guide)
9/3/2020 • 6 minutes to read • Edit Online
The actions that a program takes are expressed in statements. Common actions include declaring variables,
assigning values, calling methods, looping through collections, and branching to one or another block of code,
depending on a given condition. The order in which statements are executed in a program is called the flow of
control or flow of execution. The flow of control may vary every time that a program is run, depending on how the
program reacts to input that it receives at run time.
A statement can consist of a single line of code that ends in a semicolon, or a series of single-line statements in a
block. A statement block is enclosed in {} brackets and can contain nested blocks. The following code shows two
examples of single-line statements, and a multi-line statement block:
// Assignment statement.
counter = 1;
Types of statements
The following table lists the various types of statements in C# and their associated keywords, with links to topics
that include more information:
C AT EGO RY C # K EY W O RDS / N OT ES
Expression statements Expression statements that calculate a value must store the
value in a variable.
Checked and unchecked Checked and unchecked statements enable you to specify
whether numerical operations are allowed to cause an
overflow when the result is stored in a variable that is too
small to hold the resulting value. For more information, see
checked and unchecked.
C AT EGO RY C # K EY W O RDS / N OT ES
The await statement If you mark a method with the async modifier, you can use
the await operator in the method. When control reaches an
await expression in the async method, control returns to
the caller, and progress in the method is suspended until the
awaited task completes. When the task is complete, execution
can resume in the method.
The yield return statement An iterator performs a custom iteration over a collection, such
as a list or an array. An iterator uses the yield return
statement to return each element one at a time. When a
yield return statement is reached, the current location in
code is remembered. Execution is restarted from that location
when the iterator is called the next time.
The fixed statement The fixed statement prevents the garbage collector from
relocating a movable variable. For more information, see fixed.
The lock statement The lock statement enables you to limit access to blocks of
code to only one thread at a time. For more information, see
lock.
Labeled statements You can give a statement a label and then use the goto
keyword to jump to the labeled statement. (See the example
in the following row.)
The empty statement The empty statement consists of a single semicolon. It does
nothing and can be used in places where a statement is
required but no action needs to be performed.
Declaration statements
The following code shows examples of variable declarations with and without an initial assignment, and a constant
declaration with the necessary initialization.
Expression statements
The following code shows examples of expression statements, including assignment, object creation with
assignment, and method invocation.
// Expression statement (assignment).
area = 3.14 * (radius * radius);
void ProcessMessages()
{
while (ProcessMessage())
; // Statement needed here.
}
void F()
{
//...
if (done) goto exit;
//...
exit:
; // Statement needed here.
}
Embedded statements
Some statements, including do, while, for, and foreach, always have an embedded statement that follows them.
This embedded statement may be either a single statement or multiple statements enclosed by {} brackets in a
statement block. Even single-line embedded statements can be enclosed in {} brackets, as shown in the following
example:
// Not recommended.
foreach (string s in System.IO.Directory.GetDirectories(
System.Environment.CurrentDirectory))
System.Console.WriteLine(s);
An embedded statement that is not enclosed in {} brackets cannot be a declaration statement or a labeled
statement. This is shown in the following example:
if(pointB == true)
//Error CS1023:
int radius = 5;
Put the embedded statement in a block to fix the error:
if (b == true)
{
// OK:
System.DateTime d = System.DateTime.Now;
System.Console.WriteLine(d.ToLongDateString());
}
Unreachable statements
If the compiler determines that the flow of control can never reach a particular statement under any
circumstances, it will produce warning CS0162, as shown in the following example:
C# language specification
For more information, see the Statements section of the C# language specification.
See also
C# Programming Guide
Statement keywords
C# operators and expressions
Expression-bodied members (C# programming
guide)
9/3/2020 • 3 minutes to read • Edit Online
Expression body definitions let you provide a member's implementation in a very concise, readable form. You can
use an expression body definition whenever the logic for any supported member, such as a method or property,
consists of a single expression. An expression body definition has the following general syntax:
M EM B ER SUP P O RT ED A S O F. . .
Method C# 6
Read-only property C# 6
Property C# 7.0
Constructor C# 7.0
Finalizer C# 7.0
Indexer C# 7.0
Methods
An expression-bodied method consists of a single expression that returns a value whose type matches the
method's return type, or, for methods that return void , that performs some operation. For example, types that
override the ToString method typically include a single expression that returns the string representation of the
current object.
The following example defines a Person class that overrides the ToString method with an expression body
definition. It also defines a DisplayName method that displays a name to the console. Note that the return
keyword is not used in the ToString expression body definition.
using System;
class Example
{
static void Main()
{
Person p = new Person("Mandy", "Dejesus");
Console.WriteLine(p);
p.DisplayName();
}
}
Read-only properties
Starting with C# 6, you can use expression body definition to implement a read-only property. To do that, use the
following syntax:
The following example defines a Location class whose read-only Name property is implemented as an expression
body definition that returns the value of the private locationName field:
For more information about properties, see Properties (C# Programming Guide).
Properties
Starting with C# 7.0, you can use expression body definitions to implement property get and set accessors. The
following example demonstrates how to do that:
public class Location
{
private string locationName;
For more information about properties, see Properties (C# Programming Guide).
Constructors
An expression body definition for a constructor typically consists of a single assignment expression or a method
call that handles the constructor's arguments or initializes instance state.
The following example defines a Location class whose constructor has a single string parameter named name.
The expression body definition assigns the argument to the Name property.
Finalizers
An expression body definition for a finalizer typically contains cleanup statements, such as statements that release
unmanaged resources.
The following example defines a finalizer that uses an expression body definition to indicate that the finalizer has
been called.
using System;
Indexers
Like with properties, indexer get and set accessors consist of expression body definitions if the get accessor
consists of a single expression that returns a value or the set accessor performs a simple assignment.
The following example defines a class named Sports that includes an internal String array that contains the
names of a number of sports. Both the indexer get and set accessors are implemented as expression body
definitions.
using System;
using System.Collections.Generic;
An anonymous function is an "inline" statement or expression that can be used wherever a delegate type is
expected. You can use it to initialize a named delegate or pass it instead of a named delegate type as a method
parameter.
You can use a lambda expression or an anonymous method to create an anonymous function. We recommend
using lambda expressions as they provide more concise and expressive way to write inline code. Unlike
anonymous methods, some types of lambda expressions can be converted to the expression tree types.
C# language specification
For more information, see the Anonymous function expressions section of the C# language specification.
See also
Statements, Expressions, and Operators
Lambda Expressions
Delegates
Expression Trees (C#)
How to use lambda expressions in a query (C#
Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
You do not use lambda expressions directly in query syntax, but you do use them in method calls, and query
expressions can contain method calls. In fact, some query operations can only be expressed in method syntax. For
more information about the difference between query syntax and method syntax, see Query Syntax and Method
Syntax in LINQ.
Example
The following example demonstrates how to use a lambda expression in a method-based query by using the
Enumerable.Where standard query operator. Note that the Where method in this example has an input parameter
of the delegate type Func<T,TResult> and that delegate takes an integer as input and returns a Boolean. The
lambda expression can be converted to that delegate. If this were a LINQ to SQL query that used the
Queryable.Where method, the parameter type would be an Expression<Func<int,bool>> but the lambda expression
would look exactly the same. For more information on the Expression type, see System.Linq.Expressions.Expression.
class SimpleLambda
{
static void Main()
{
// Data source.
int[] scores = { 90, 71, 82, 93, 75, 82 };
Example
The following example demonstrates how to use a lambda expression in a method call of a query expression. The
lambda is necessary because the Sum standard query operator cannot be invoked by using query syntax.
The query first groups the students according to their grade level, as defined in the GradeLevel enum. Then for
each group it adds the total scores for each student. This requires two Sum operations. The inner Sum calculates
the total score for each student, and the outer Sum keeps a running, combined total for all students in the group.
private static void TotalsByGradeLevel()
{
// This query retrieves the total scores for First Year students, Second Years, and so on.
// The outer Sum method uses a lambda in order to specify which numbers to add together.
var categories =
from student in students
group student by student.Year into studentGroup
select new { GradeLevel = studentGroup.Key, TotalScore = studentGroup.Sum(s => s.ExamScores.Sum()) };
See also
Lambda Expressions
Expression Trees (C#)
Equality comparisons (C# Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
It is sometimes necessary to compare two values for equality. In some cases, you are testing for value equality, also
known as equivalence, which means that the values that are contained by the two variables are equal. In other
cases, you have to determine whether two variables refer to the same underlying object in memory. This type of
equality is called reference equality, or identity. This topic describes these two kinds of equality and provides links
to other topics for more information.
Reference equality
Reference equality means that two object references refer to the same underlying object. This can occur through
simple assignment, as shown in the following example.
using System;
class Test
{
public int Num { get; set; }
public string Str { get; set; }
// Assign b to a.
b = a;
In this code, two objects are created, but after the assignment statement, both references refer to the same object.
Therefore they have reference equality. Use the ReferenceEquals method to determine whether two references
refer to the same object.
The concept of reference equality applies only to reference types. Value type objects cannot have reference equality
because when an instance of a value type is assigned to a variable, a copy of the value is made. Therefore you can
never have two unboxed structs that refer to the same location in memory. Furthermore, if you use
ReferenceEquals to compare two value types, the result will always be false , even if the values that are contained
in the objects are all identical. This is because each variable is boxed into a separate object instance. For more
information, see How to test for reference equality (Identity).
Value equality
Value equality means that two objects contain the same value or values. For primitive value types such as int or
bool, tests for value equality are straightforward. You can use the == operator, as shown in the following example.
int a = GetOriginalValue();
int b = GetCurrentValue();
For most other types, testing for value equality is more complex because it requires that you understand how the
type defines it. For classes and structs that have multiple fields or properties, value equality is often defined to
mean that all fields or properties have the same value. For example, two Point objects might be defined to be
equivalent if pointA.X is equal to pointB.X and pointA.Y is equal to pointB.Y.
However, there is no requirement that equivalence be based on all the fields in a type. It can be based on a subset.
When you compare types that you do not own, you should make sure to understand specifically how equivalence
is defined for that type. For more information about how to define value equality in your own classes and structs,
see How to define value equality for a type.
Value equality for floating-point values
Equality comparisons of floating-point values (double and float) are problematic because of the imprecision of
floating-point arithmetic on binary computers. For more information, see the remarks in the topic System.Double.
Related topics
T IT L E DESC RIP T IO N
How to test for reference equality (Identity) Describes how to determine whether two variables have
reference equality.
How to define value equality for a type Describes how to provide a custom definition of value equality
for a type.
See also
C# Programming Guide
How to define value equality for a type (C#
Programming Guide)
9/3/2020 • 8 minutes to read • Edit Online
When you define a class or struct, you decide whether it makes sense to create a custom definition of value
equality (or equivalence) for the type. Typically, you implement value equality when objects of the type are
expected to be added to a collection of some sort, or when their primary purpose is to store a set of fields or
properties. You can base your definition of value equality on a comparison of all the fields and properties in the
type, or you can base the definition on a subset.
In either case, and in both classes and structs, your implementation should follow the five guarantees of
equivalence (For the following rules, assume that x , y and z are not null):
1. x.Equals(x) returns true . This is called the reflexive property.
2. x.Equals(y) returns the same value as y.Equals(x) . This is called the symmetric property.
3. if (x.Equals(y) && y.Equals(z)) returns true , then x.Equals(z) returns true . This is called the transitive
property.
4. Successive invocations of x.Equals(y) return the same value as long as the objects referenced by x and y
are not modified.
5. Any non-null value is not equal to null. However, the CLR checks for null on all method calls and throws a
NullReferenceException if the this reference would be null. Therefore, x.Equals(y) throws an exception
when x is null. That breaks rules 1 or 2, depending on the argument to Equals .
Any struct that you define already has a default implementation of value equality that it inherits from the
System.ValueType override of the Object.Equals(Object) method. This implementation uses reflection to examine
all the fields and properties in the type. Although this implementation produces correct results, it is relatively slow
compared to a custom implementation that you write specifically for the type.
The implementation details for value equality are different for classes and structs. However, both classes and
structs require the same basic steps for implementing equality:
1. Override the virtual Object.Equals(Object) method. In most cases, your implementation of
bool Equals( object obj ) should just call into the type-specific Equals method that is the implementation
of the System.IEquatable<T> interface. (See step 2.)
2. Implement the System.IEquatable<T> interface by providing a type-specific Equals method. This is where
the actual equivalence comparison is performed. For example, you might decide to define equality by
comparing only one or two fields in your type. Do not throw exceptions from Equals . For classes only: This
method should examine only fields that are declared in the class. It should call base.Equals to examine
fields that are in the base class. (Do not do this if the type inherits directly from Object, because the Object
implementation of Object.Equals(Object) performs a reference equality check.)
3. Optional but recommended: Overload the == and != operators.
4. Override Object.GetHashCode so that two objects that have value equality produce the same hash code.
5. Optional: To support definitions for "greater than" or "less than," implement the IComparable<T> interface
for your type, and also overload the <= and >= operators.
The first example that follows shows a class implementation. The second example shows a struct implementation.
Example
The following example shows how to implement value equality in a class (reference type).
namespace ValueEquality
{
using System;
class TwoDPoint : IEquatable<TwoDPoint>
{
// Readonly auto-implemented properties.
public int X { get; private set; }
public int Y { get; private set; }
class Program
{
static void Main(string[] args)
{
ThreeDPoint pointA = new ThreeDPoint(3, 4, 5);
ThreeDPoint pointB = new ThreeDPoint(3, 4, 5);
ThreeDPoint pointC = null;
int i = 5;
/* Output:
pointA.Equals(pointB) = True
pointA == pointB = True
null comparison = False
Compare to some other type = False
Two null TwoDPoints are equal: True
(pointE == pointA) = False
(pointA == pointE) = False
(pointA != pointE) = True
(pointA != pointE) = True
pointE.Equals(list[0]): False
*/
}
On classes (reference types), the default implementation of both Object.Equals(Object) methods performs a
reference equality comparison, not a value equality check. When an implementer overrides the virtual method, the
purpose is to give it value equality semantics.
The == and != operators can be used with classes even if the class does not overload them. However, the default
behavior is to perform a reference equality check. In a class, if you overload the Equals method, you should
overload the == and != operators, but it is not required.
Example
The following example shows how to implement value equality in a struct (value type):
using System;
struct TwoDPoint : IEquatable<TwoDPoint>
{
// Read/write auto-implemented properties.
public int X { get; private set; }
public int Y { get; private set; }
class Program
{
static void Main(string[] args)
{
TwoDPoint pointA = new TwoDPoint(3, 4);
TwoDPoint pointB = new TwoDPoint(3, 4);
int i = 5;
pointD = temp;
// True:
Console.WriteLine("pointD == (pointC = 3,4) = {0}", pointD == pointC);
/* Output:
pointA.Equals(pointB) = True
pointA == pointB = True
Object.Equals(pointA, pointB) = True
pointA.Equals(null) = False
(pointA == null) = False
(pointA != null) = True
pointA.Equals(i) = False
pointE.Equals(list[0]): True
pointA == (pointC = null) = False
pointC == pointD = True
pointA == (pointC = 3,4) = True
pointD == (pointC = 3,4) = True
*/
}
For structs, the default implementation of Object.Equals(Object) (which is the overridden version in
System.ValueType) performs a value equality check by using reflection to compare the values of every field in the
type. When an implementer overrides the virtual Equals method in a struct, the purpose is to provide a more
efficient means of performing the value equality check and optionally to base the comparison on some subset of
the struct's field or properties.
The == and != operators cannot operate on a struct unless the struct explicitly overloads them.
See also
Equality comparisons
C# programming guide
How to test for reference equality (Identity) (C#
Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
You do not have to implement any custom logic to support reference equality comparisons in your types. This
functionality is provided for all types by the static Object.ReferenceEquals method.
The following example shows how to determine whether two variables have reference equality, which means that
they refer to the same object in memory.
The example also shows why Object.ReferenceEquals always returns false for value types and why you should
not use ReferenceEquals to determine string equality.
Example
namespace TestReferenceEquality
{
struct TestStruct
{
public int Num { get; private set; }
public string Name { get; private set; }
class TestClass
{
public int Num { get; set; }
public string Name { get; set; }
}
class Program
{
static void Main()
{
// Demonstrate reference equality with reference types.
#region ReferenceTypes
// Demonstrate that two value type instances never have reference equality.
#region ValueTypes
#region stringRefEquality
// Constant strings within the same assembly are always interned by the runtime.
// This means they are stored in the same location in memory. Therefore,
// the two strings have reference equality although no assignment takes place.
string strA = "Hello world!";
string strB = "Hello world!";
Console.WriteLine("ReferenceEquals(strA, strB) = {0}",
Object.ReferenceEquals(strA, strB)); // true
#endregion
/* Output:
ReferenceEquals(tcA, tcB) = False
After assignment: ReferenceEquals(tcA, tcB) = True
tcB.Name = TestClass 42 tcB.Num: 42
After assignment: ReferenceEquals(tsC, tsD) = False
ReferenceEquals(strA, strB) = True
strA = "Goodbye world!" strB = "Hello world!"
After strA changes, ReferenceEquals(strA, strB) = False
*/
The implementation of Equals in the System.Object universal base class also performs a reference equality check,
but it is best not to use this because, if a class happens to override the method, the results might not be what you
expect. The same is true for the == and != operators. When they are operating on reference types, the default
behavior of == and != is to perform a reference equality check. However, derived classes can overload the
operator to perform a value equality check. To minimize the potential for error, it is best to always use
ReferenceEquals when you have to determine whether two objects have reference equality.
Constant strings within the same assembly are always interned by the runtime. That is, only one instance of each
unique literal string is maintained. However, the runtime does not guarantee that strings created at runtime are
interned, nor does it guarantee that two equal constant strings in different assemblies are interned.
See also
Equality Comparisons
Types (C# Programming Guide)
9/3/2020 • 11 minutes to read • Edit Online
int a = 5;
int b = a + 2; //OK
// Error. Operator '+' cannot be applied to operands of type 'int' and 'bool'.
int c = a + test;
NOTE
C and C++ developers, notice that in C#, bool is not convertible to int.
The compiler embeds the type information into the executable file as metadata. The common language runtime
(CLR) uses that metadata at run time to further guarantee type safety when it allocates and reclaims memory.
Specifying types in variable declarations
When you declare a variable or constant in a program, you must either specify its type or use the var keyword to
let the compiler infer the type. The following example shows some variable declarations that use both built-in
numeric types and complex user-defined types:
// Declaration only:
float temperature;
string name;
MyClass myClass;
The types of method parameters and return values are specified in the method declaration. The following
signature shows a method that requires an int as an input argument and returns a string:
After a variable is declared, it cannot be re-declared with a new type, and it cannot be assigned a value that is not
compatible with its declared type. For example, you cannot declare an int and then assign it a Boolean value of
true . However, values can be converted to other types, for example when they are assigned to new variables or
passed as method arguments. A type conversion that does not cause data loss is performed automatically by the
compiler. A conversion that might cause data loss requires a cast in the source code.
For more information, see Casting and Type Conversions.
Built-in types
C# provides a standard set of built-in numeric types to represent integers, floating point values, Boolean
expressions, text characters, decimal values, and other types of data. There are also built-in string and object
types. These are available for you to use in any C# program. For the complete list of the built-in types, see Built-in
types.
Custom types
You use the struct, class, interface, and enum constructs to create your own custom types. The .NET class library
itself is a collection of custom types provided by Microsoft that you can use in your own applications. By default,
the most frequently used types in the class library are available in any C# program. Others become available
only when you explicitly add a project reference to the assembly in which they are defined. After the compiler
has a reference to the assembly, you can declare variables (and constants) of the types declared in that assembly
in source code. For more information, see .NET Class Library.
NOTE
You can see that the most commonly used types are all organized in the System namespace. However, the namespace in
which a type is contained has no relation to whether it is a value type or reference type.
Value types
Value types derive from System.ValueType, which derives from System.Object. Types that derive from
System.ValueType have special behavior in the CLR. Value type variables directly contain their values, which
means that the memory is allocated inline in whatever context the variable is declared. There is no separate heap
allocation or garbage collection overhead for value-type variables.
There are two categories of value types: struct and enum.
The built-in numeric types are structs, and they have fields and methods that you can access:
But you declare and assign values to them as if they were simple non-aggregate types:
byte num = 0xA;
int i = 5;
char c = 'Z';
Value types are sealed, which means, for example, that you cannot derive a type from System.Int32, and you
cannot define a struct to inherit from any user-defined class or struct because a struct can only inherit from
System.ValueType. However, a struct can implement one or more interfaces. You can cast a struct type to any
interface type that it implements; this causes a boxing operation to wrap the struct inside a reference type object
on the managed heap. Boxing operations occur when you pass a value type to a method that takes a
System.Object or any interface type as an input parameter. For more information, see Boxing and Unboxing.
You use the struct keyword to create your own custom value types. Typically, a struct is used as a container for a
small set of related variables, as shown in the following example:
For more information about structs, see Structure types. For more information about value types, see Value
types.
The other category of value types is enum. An enum defines a set of named integral constants. For example, the
System.IO.FileMode enumeration in the .NET class library contains a set of named constant integers that specify
how a file should be opened. It is defined as shown in the following example:
The System.IO.FileMode.Create constant has a value of 2. However, the name is much more meaningful for
humans reading the source code, and for that reason it is better to use enumerations instead of constant literal
numbers. For more information, see System.IO.FileMode.
All enums inherit from System.Enum, which inherits from System.ValueType. All the rules that apply to structs
also apply to enums. For more information about enums, see Enumeration types.
Reference types
A type that is defined as a class, delegate, array, or interface is a reference type. At run time, when you declare a
variable of a reference type, the variable contains the value null until you explicitly create an object by using the
new operator, or assign it an object that has been created elsewhere by using new , as shown in the following
example:
MyClass mc = new MyClass();
MyClass mc2 = mc;
An interface must be initialized together with a class object that implements it. If MyClass implements
IMyInterface , you create an instance of IMyInterface as shown in the following example:
When the object is created, the memory is allocated on the managed heap, and the variable holds only a
reference to the location of the object. Types on the managed heap require overhead both when they are
allocated and when they are reclaimed by the automatic memory management functionality of the CLR, which is
known as garbage collection. However, garbage collection is also highly optimized, and in most scenarios it does
not create a performance issue. For more information about garbage collection, see Automatic Memory
Management.
All arrays are reference types, even if their elements are value types. Arrays implicitly derive from the
System.Array class, but you declare and use them with the simplified syntax that is provided by C#, as shown in
the following example:
Reference types fully support inheritance. When you create a class, you can inherit from any other interface or
class that is not defined as sealed, and other classes can inherit from your class and override your virtual
methods. For more information about how to create your own classes, see Classes and Structs. For more
information about inheritance and virtual methods, see Inheritance.
Generic types
A type can be declared with one or more type parameters that serve as a placeholder for the actual type (the
concrete type) that client code will provide when it creates an instance of the type. Such types are called generic
types. For example, the .NET type System.Collections.Generic.List<T> has one type parameter that by convention
is given the name T. When you create an instance of the type, you specify the type of the objects that the list will
contain, for example, string:
The use of the type parameter makes it possible to reuse the same class to hold any type of element, without
having to convert each element to object. Generic collection classes are called strongly typed collections because
the compiler knows the specific type of the collection's elements and can raise an error at compile-time if, for
example, you try to add an integer to the stringList object in the previous example. For more information, see
Generics.
Related sections
For more information, see the following topics:
Casting and Type Conversions
Boxing and Unboxing
Using Type dynamic
Value Types
Reference Types
Classes and Structs
Anonymous Types
Generics
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Reference
C# Programming Guide
Conversion of XML Data Types
Integral types
Casting and type conversions (C# Programming
Guide)
9/3/2020 • 5 minutes to read • Edit Online
Because C# is statically-typed at compile time, after a variable is declared, it cannot be declared again or assigned
a value of another type unless that type is implicitly convertible to the variable's type. For example, the string
cannot be implicitly converted to int . Therefore, after you declare i as an int , you cannot assign the string
"Hello" to it, as the following code shows:
int i;
However, you might sometimes need to copy a value into a variable or method parameter of another type. For
example, you might have an integer variable that you need to pass to a method whose parameter is typed as
double . Or you might need to assign a class variable to a variable of an interface type. These kinds of operations
are called type conversions. In C#, you can perform the following kinds of conversions:
Implicit conversions : No special syntax is required because the conversion always succeeds and no data
will be lost. Examples include conversions from smaller to larger integral types, and conversions from
derived classes to base classes.
Explicit conversions (casts) : Explicit conversions require a cast expression. Casting is required when
information might be lost in the conversion, or when the conversion might not succeed for other reasons.
Typical examples include numeric conversion to a type that has less precision or a smaller range, and
conversion of a base-class instance to a derived class.
User-defined conversions : User-defined conversions are performed by special methods that you can
define to enable explicit and implicit conversions between custom types that do not have a base class–
derived class relationship. For more information, see User-defined conversion operators.
Conversions with helper classes : To convert between non-compatible types, such as integers and
System.DateTime objects, or hexadecimal strings and byte arrays, you can use the System.BitConverter
class, the System.Convert class, and the Parse methods of the built-in numeric types, such as Int32.Parse.
For more information, see How to convert a byte array to an int, How to convert a string to a number, and
How to convert between hexadecimal strings and numeric types.
Implicit conversions
For built-in numeric types, an implicit conversion can be made when the value to be stored can fit into the
variable without being truncated or rounded off. For integral types, this means the range of the source type is a
proper subset of the range for the target type. For example, a variable of type long (64-bit integer) can store any
value that an int (32-bit integer) can store. In the following example, the compiler implicitly converts the value of
num on the right to a type long before assigning it to bigNum .
// Implicit conversion. A long can
// hold any value an int can hold, and more!
int num = 2147483647;
long bigNum = num;
For a complete list of all implicit numeric conversions, see the Implicit numeric conversions section of the Built-in
numeric conversions article.
For reference types, an implicit conversion always exists from a class to any one of its direct or indirect base
classes or interfaces. No special syntax is necessary because a derived class always contains all the members of a
base class.
// Always OK.
Base b = d;
Explicit conversions
However, if a conversion cannot be made without a risk of losing information, the compiler requires that you
perform an explicit conversion, which is called a cast. A cast is a way of explicitly informing the compiler that you
intend to make the conversion and that you are aware that data loss might occur, or the cast may fail at runtime.
To perform a cast, specify the type that you are casting to in parentheses in front of the value or variable to be
converted. The following program casts a double to an int. The program will not compile without the cast.
class Test
{
static void Main()
{
double x = 1234.7;
int a;
// Cast double to int.
a = (int)x;
System.Console.WriteLine(a);
}
}
// Output: 1234
For a complete list of supported explicit numeric conversions, see the Explicit numeric conversions section of the
Built-in numeric conversions article.
For reference types, an explicit cast is required if you need to convert from a base type to a derived type:
A cast operation between reference types does not change the run-time type of the underlying object; it only
changes the type of the value that is being used as a reference to that object. For more information, see
Polymorphism.
class Animal
{
public void Eat() => System.Console.WriteLine("Eating.");
class UnSafeCast
{
static void Main()
{
Test(new Mammal());
The Test method has an Animal parameter, thus explicitly casting the argument a to a Reptile makes a
dangerous assumption. It is safer to not make assumptions, but rather check the type. C# provides the is operator
to enable you to test for compatibility before actually performing a cast. For more information, see How to safely
cast using pattern matching and the as and is operators.
C# language specification
For more information, see the Conversions section of the C# language specification.
See also
C# Programming Guide
Types
Cast expression
User-defined conversion operators
Generalized Type Conversion
How to convert a string to a number
Boxing and Unboxing (C# Programming Guide)
9/3/2020 • 5 minutes to read • Edit Online
Boxing is the process of converting a value type to the type object or to any interface type implemented by this
value type. When the common language runtime (CLR) boxes a value type, it wraps the value inside a
System.Object instance and stores it on the managed heap. Unboxing extracts the value type from the object.
Boxing is implicit; unboxing is explicit. The concept of boxing and unboxing underlies the C# unified view of the
type system in which a value of any type can be treated as an object.
In the following example, the integer variable i is boxed and assigned to object o .
int i = 123;
// The following line boxes i.
object o = i;
o = 123;
i = (int)o; // unboxing
// String.Concat example.
// String.Concat has many versions. Rest the mouse pointer on
// Concat in the following statement to verify that the version
// that is used here takes three object arguments. Both 42 and
// true must be boxed.
Console.WriteLine(String.Concat("Answer", 42, true));
// List example.
// Create a list of objects to hold a heterogeneous collection
// of elements.
List<object> mixedList = new List<object>();
// The following loop sums the squares of the first group of boxed
// integers in mixedList. The list elements are objects, and cannot
// be multiplied or added to the sum until they are unboxed. The
// unboxing must be done explicitly.
var sum = 0;
for (var j = 1; j < 5; j++)
{
// The following statement causes a compiler error: Operator
// '*' cannot be applied to operands of type 'object' and
// 'object'.
//sum += mixedList[j] * mixedList[j]);
// Output:
// Answer42True
// First Group:
// 1
// 2
// 3
// 4
// Second Group:
// 5
// 6
// 7
// 8
// 9
// Sum: 30
Performance
In relation to simple assignments, boxing and unboxing are computationally expensive processes. When a value
type is boxed, a new object must be allocated and constructed. To a lesser degree, the cast required for unboxing
is also expensive computationally. For more information, see Performance.
Boxing
Boxing is used to store value types in the garbage-collected heap. Boxing is an implicit conversion of a value type
to the type object or to any interface type implemented by this value type. Boxing a value type allocates an
object instance on the heap and copies the value into the new object.
Consider the following declaration of a value-type variable:
int i = 123;
The following statement implicitly applies the boxing operation on the variable i :
It is also possible to perform the boxing explicitly as in the following example, but explicit boxing is never
required:
int i = 123;
object o = (object)i; // explicit boxing
Description
This example converts an integer variable i to an object o by using boxing. Then, the value stored in the
variable i is changed from 123 to 456 . The example shows that the original value type and the boxed object
use separate memory locations, and therefore can store different values.
Example
class TestBoxing
{
static void Main()
{
int i = 123;
Unboxing
Unboxing is an explicit conversion from the type object to a value type or from an interface type to a value type
that implements the interface. An unboxing operation consists of:
Checking the object instance to make sure that it is a boxed value of the given value type.
Copying the value from the instance into the value-type variable.
The following statements demonstrate both boxing and unboxing operations:
int i = 123; // a value type
object o = i; // boxing
int j = (int)o; // unboxing
For the unboxing of value types to succeed at run time, the item being unboxed must be a reference to an object
that was previously created by boxing an instance of that value type. Attempting to unbox null causes a
NullReferenceException. Attempting to unbox a reference to an incompatible value type causes an
InvalidCastException.
Example
The following example demonstrates a case of invalid unboxing and the resulting InvalidCastException . Using
try and catch , an error message is displayed when the error occurs.
class TestUnboxing
{
static void Main()
{
int i = 123;
object o = i; // implicit boxing
try
{
int j = (short)o; // attempt to unbox
System.Console.WriteLine("Unboxing OK.");
}
catch (System.InvalidCastException e)
{
System.Console.WriteLine("{0} Error: Incorrect unboxing.", e.Message);
}
}
}
int j = (short) o;
to:
int j = (int) o;
the conversion will be performed, and you will get the output:
Unboxing OK.
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# programming guide
Reference types
Value types
How to convert a byte array to an int (C#
Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
This example shows you how to use the BitConverter class to convert an array of bytes to an int and back to an
array of bytes. You may have to convert from bytes to a built-in data type after you read bytes off the network, for
example. In addition to the ToInt32(Byte[], Int32) method in the example, the following table lists methods in the
BitConverter class that convert bytes (from an array of bytes) to other built-in types.
T Y P E RET URN ED M ET H O D
Example
This example initializes an array of bytes, reverses the array if the computer architecture is little-endian (that is, the
least significant byte is stored first), and then calls the ToInt32(Byte[], Int32) method to convert four bytes in the
array to an int . The second argument to ToInt32(Byte[], Int32) specifies the start index of the array of bytes.
NOTE
The output may differ depending on the endianness of your computer's architecture.
byte[] bytes = { 0, 0, 0, 25 };
Example
In this example, the GetBytes(Int32) method of the BitConverter class is called to convert an int to an array of
bytes.
NOTE
The output may differ depending on the endianness of your computer's architecture.
See also
BitConverter
IsLittleEndian
Types
How to convert a string to a number (C#
Programming Guide)
9/3/2020 • 4 minutes to read • Edit Online
You can convert a string to a number by calling the Parse or TryParse method found on the various numeric
types ( int , long , double , etc.), or by using methods in the System.Convert class.
If you have a string, it is slightly more efficient and straightforward to call a TryParse method (for example,
int.TryParse("11", out number) ) or Parse method (for example, var number = int.Parse("11") ). Using a Convert
method is more useful for general objects that implement IConvertible.
You can use Parse or TryParse methods on the numeric type you expect the string contains, such as the
System.Int32 type. The Convert.ToInt32 method uses Parse internally. The Parse method returns the converted
number; the TryParse method returns a Boolean value that indicates whether the conversion succeeded, and
returns the converted number in an out parameter. If the string is not in a valid format, Parse throws an
exception, whereas TryParse returns false . When calling a Parse method, you should always use exception
handling to catch a FormatException in the event that the parse operation fails.
try
{
int numVal = Int32.Parse("-105");
Console.WriteLine(numVal);
}
catch (FormatException e)
{
Console.WriteLine(e.Message);
}
// Output: -105
try
{
int m = Int32.Parse("abc");
}
catch (FormatException e)
{
Console.WriteLine(e.Message);
}
// Output: Input string was not in a correct format.
The following example illustrates one a approach to parsing a string that is expected to include leading numeric
characters (including hexadecimal characters) and trailing non-numeric characters. It assigns valid characters from
the beginning of a string to a new string before calling the TryParse method. Because the strings to be parsed
contain a small number of characters, the example calls the String.Concat method to assign valid characters to a
new string. For a larger string, the StringBuilder class can be used instead.
using System;
N UM ERIC T Y P E M ET H O D
decimal ToDecimal(String)
float ToSingle(String)
double ToDouble(String)
short ToInt16(String)
int ToInt32(String)
long ToInt64(String)
N UM ERIC T Y P E M ET H O D
ushort ToUInt16(String)
uint ToUInt32(String)
ulong ToUInt64(String)
The following example calls the Convert.ToInt32(String) method to convert an input string to an int. The example
catches the two most common exceptions that can be thrown by this method, FormatException and
OverflowException. If the resulting number can be incremented without exceeding Int32.MaxValue, the example
adds 1 to the result and displays the output.
using System;
while (repeat)
{
Console.Write("Enter a number between −2,147,483,648 and +2,147,483,647 (inclusive): ");
See also
Types
How to determine whether a string represents a numeric value
Sample: .NET Core WinForms Formatting Utility (C#)
How to convert between hexadecimal strings and
numeric types (C# Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
Example
This example outputs the hexadecimal value of each character in a string . First it parses the string to an array
of characters. Then it calls ToInt32(Char) on each character to obtain its numeric value. Finally, it formats the
number as its hexadecimal representation in a string .
Example
This example parses a string of hexadecimal values and outputs the character corresponding to each
hexadecimal value. First it calls the Split(Char[]) method to obtain each hexadecimal value as an individual string
in an array. Then it calls ToInt32(String, Int32) to convert the hexadecimal value to a decimal value represented as
an int. It shows two different ways to obtain the character corresponding to that character code. The first technique
uses ConvertFromUtf32(Int32), which returns the character corresponding to the integer argument as a string .
The second technique explicitly casts the int to a char.
string hexValues = "48 65 6C 6C 6F 20 57 6F 72 6C 64 21";
string[] hexValuesSplit = hexValues.Split(' ');
foreach (string hex in hexValuesSplit)
{
// Convert the number expressed in base-16 to an integer.
int value = Convert.ToInt32(hex, 16);
// Get the character corresponding to the integral value.
string stringValue = Char.ConvertFromUtf32(value);
char charValue = (char)value;
Console.WriteLine("hexadecimal value = {0}, int value = {1}, char value = {2} or {3}",
hex, value, stringValue, charValue);
}
/* Output:
hexadecimal value = 48, int value = 72, char value = H or H
hexadecimal value = 65, int value = 101, char value = e or e
hexadecimal value = 6C, int value = 108, char value = l or l
hexadecimal value = 6C, int value = 108, char value = l or l
hexadecimal value = 6F, int value = 111, char value = o or o
hexadecimal value = 20, int value = 32, char value = or
hexadecimal value = 57, int value = 87, char value = W or W
hexadecimal value = 6F, int value = 111, char value = o or o
hexadecimal value = 72, int value = 114, char value = r or r
hexadecimal value = 6C, int value = 108, char value = l or l
hexadecimal value = 64, int value = 100, char value = d or d
hexadecimal value = 21, int value = 33, char value = ! or !
*/
Example
This example shows another way to convert a hexadecimal string to an integer, by calling the Parse(String,
NumberStyles) method.
Example
The following example shows how to convert a hexadecimal string to a float by using the System.BitConverter
class and the UInt32.Parse method.
// Output: 200.0056
Example
The following example shows how to convert a byte array to a hexadecimal string by using the
System.BitConverter class.
byte[] vals = { 0x01, 0xAA, 0xB1, 0xDC, 0x10, 0xDD };
/*Output:
01-AA-B1-DC-10-DD
01AAB1DC10DD
*/
See also
Standard Numeric Format Strings
Types
How to determine whether a string represents a numeric value
Using type dynamic (C# Programming Guide)
9/3/2020 • 5 minutes to read • Edit Online
C# 4 introduces a new type, dynamic . The type is a static type, but an object of type dynamic bypasses static type
checking. In most cases, it functions like it has type object . At compile time, an element that is typed as dynamic
is assumed to support any operation. Therefore, you do not have to be concerned about whether the object gets
its value from a COM API, from a dynamic language such as IronPython, from the HTML Document Object Model
(DOM), from reflection, or from somewhere else in the program. However, if the code is not valid, errors are
caught at run time.
For example, if instance method exampleMethod1 in the following code has only one parameter, the compiler
recognizes that the first call to the method, ec.exampleMethod1(10, 4) , is not valid because it contains two
arguments. The call causes a compiler error. The second call to the method, dynamic_ec.exampleMethod1(10, 4) , is
not checked by the compiler because the type of dynamic_ec is dynamic . Therefore, no compiler error is reported.
However, the error does not escape notice indefinitely. It is caught at run time and causes a run-time exception.
class ExampleClass
{
public ExampleClass() { }
public ExampleClass(int v) { }
The role of the compiler in these examples is to package together information about what each statement is
proposing to do to the object or expression that is typed as dynamic . At run time, the stored information is
examined, and any statement that is not valid causes a run-time exception.
The result of most dynamic operations is itself dynamic . For example, if you rest the mouse pointer over the use
of testSum in the following example, IntelliSense displays the type (local variable) dynamic testSum .
dynamic d = 1;
var testSum = d + 3;
// Rest the mouse pointer over testSum in the following statement.
System.Console.WriteLine(testSum);
Conversions
Conversions between dynamic objects and other types are easy. This enables the developer to switch between
dynamic and non-dynamic behavior.
Any object can be converted to dynamic type implicitly, as shown in the following examples.
dynamic d1 = 7;
dynamic d2 = "a string";
dynamic d3 = System.DateTime.Today;
dynamic d4 = System.Diagnostics.Process.GetProcesses();
Conversely, an implicit conversion can be dynamically applied to any expression of type dynamic .
int i = d1;
string str = d2;
DateTime dt = d3;
System.Diagnostics.Process[] procs = d4;
// Valid.
ec.exampleMethod2("a string");
// The following statement does not cause a compiler error, even though ec is not
// dynamic. A run-time exception is raised because the run-time type of d1 is int.
ec.exampleMethod2(d1);
// The following statement does cause a compiler error.
//ec.exampleMethod2(7);
COM interop
C# 4 includes several features that improve the experience of interoperating with COM APIs such as the Office
Automation APIs. Among the improvements are the use of the dynamic type, and of named and optional
arguments.
Many COM methods allow for variation in argument types and return type by designating the types as object .
This has necessitated explicit casting of the values to coordinate with strongly typed variables in C#. If you
compile by using the -link (C# Compiler Options) option, the introduction of the dynamic type enables you to
treat the occurrences of object in COM signatures as if they were of type dynamic , and thereby to avoid much of
the casting. For example, the following statements contrast how you access a cell in a Microsoft Office Excel
spreadsheet with the dynamic type and without the dynamic type.
// After the introduction of dynamic, the access to the Value property and
// the conversion to Excel.Range are handled by the run-time COM binder.
excelApp.Cells[1, 1].Value = "Name";
Excel.Range range2010 = excelApp.Cells[1, 1];
Related topics
T IT L E DESC RIP T IO N
Dynamic Language Runtime Overview Provides an overview of the DLR, which is a runtime
environment that adds a set of services for dynamic
languages to the common language runtime (CLR).
Walkthrough: Creating and Using Dynamic Objects Provides step-by-step instructions for creating a custom
dynamic object and for creating a project that accesses an
IronPython library.
How to access Office interop objects by using C# features Demonstrates how to create a project that uses named and
optional arguments, the dynamic type, and other
enhancements that simplify access to Office API objects.
Walkthrough: Creating and Using Dynamic Objects
(C# and Visual Basic)
9/3/2020 • 11 minutes to read • Edit Online
Dynamic objects expose members such as properties and methods at run time, instead of at compile time. This
enables you to create objects to work with structures that do not match a static type or format. For example, you
can use a dynamic object to reference the HTML Document Object Model (DOM), which can contain any
combination of valid HTML markup elements and attributes. Because each HTML document is unique, the
members for a particular HTML document are determined at run time. A common method to reference an
attribute of an HTML element is to pass the name of the attribute to the GetProperty method of the element. To
reference the id attribute of the HTML element <div id="Div1"> , you first obtain a reference to the <div>
element, and then use divElement.GetProperty("id") . If you use a dynamic object, you can reference the id
attribute as divElement.id .
Dynamic objects also provide convenient access to dynamic languages such as IronPython and IronRuby. You can
use a dynamic object to refer to a dynamic script that is interpreted at run time.
You reference a dynamic object by using late binding. In C#, you specify the type of a late-bound object as dynamic
. In Visual Basic, you specify the type of a late-bound object as Object . For more information, see dynamic and
Early and Late Binding.
You can create custom dynamic objects by using the classes in the System.Dynamic namespace. For example, you
can create an ExpandoObject and specify the members of that object at run time. You can also create your own
type that inherits the DynamicObject class. You can then override the members of the DynamicObject class to
provide run-time dynamic functionality.
In this walkthrough you will perform the following tasks:
Create a custom object that dynamically exposes the contents of a text file as properties of an object.
Create a project that uses an IronPython library.
Prerequisites
You need IronPython for .NET to complete this walkthrough. Go to their Download page to obtain the latest
version.
NOTE
Your computer might show different names or locations for some of the Visual Studio user interface elements in the following
instructions. The Visual Studio edition that you have and the settings that you use determine these elements. For more
information, see Personalizing the IDE.
5. At the top of the ReadOnlyFile.cs or ReadOnlyFile.vb file, add the following code to import the System.IO
and System.Dynamic namespaces.
using System.IO;
using System.Dynamic;
Imports System.IO
Imports System.Dynamic
6. The custom dynamic object uses an enum to determine the search criteria. Before the class statement, add
the following enum definition.
7. Update the class statement to inherit the DynamicObject class, as shown in the following code example.
8. Add the following code to the ReadOnlyFile class to define a private field for the file path and a constructor
for the ReadOnlyFile class.
// Store the path to the file and the initial line count value.
private string p_filePath;
// Public constructor. Verify that file exists and store the path in
// the private variable.
public ReadOnlyFile(string filePath)
{
if (!File.Exists(filePath))
{
throw new Exception("File path does not exist.");
}
p_filePath = filePath;
}
' Store the path to the file and the initial line count value.
Private p_filePath As String
' Public constructor. Verify that file exists and store the path in
' the private variable.
Public Sub New(ByVal filePath As String)
If Not File.Exists(filePath) Then
Throw New Exception("File path does not exist.")
End If
p_filePath = filePath
End Sub
9. Add the following GetPropertyValue method to the ReadOnlyFile class. The GetPropertyValue method
takes, as input, search criteria and returns the lines from a text file that match that search criteria. The
dynamic methods provided by the ReadOnlyFile class call the GetPropertyValue method to retrieve their
respective results.
public List<string> GetPropertyValue(string propertyName,
StringSearchOption StringSearchOption =
StringSearchOption.StartsWith,
bool trimSpaces = true)
{
StreamReader sr = null;
List<string> results = new List<string>();
string line = "";
string testLine = "";
try
{
sr = new StreamReader(p_filePath);
while (!sr.EndOfStream)
{
line = sr.ReadLine();
switch (StringSearchOption)
{
case StringSearchOption.StartsWith:
if (testLine.StartsWith(propertyName.ToUpper())) { results.Add(line); }
break;
case StringSearchOption.Contains:
if (testLine.Contains(propertyName.ToUpper())) { results.Add(line); }
break;
case StringSearchOption.EndsWith:
if (testLine.EndsWith(propertyName.ToUpper())) { results.Add(line); }
break;
}
}
}
catch
{
// Trap any exception that occurs in reading the file and return null.
results = null;
}
finally
{
if (sr != null) {sr.Close();}
}
return results;
}
Public Function GetPropertyValue(ByVal propertyName As String,
Optional ByVal StringSearchOption As StringSearchOption =
StringSearchOption.StartsWith,
Optional ByVal trimSpaces As Boolean = True) As List(Of String)
Try
sr = New StreamReader(p_filePath)
Return results
End Function
10. After the GetPropertyValue method, add the following code to override the TryGetMember method of the
DynamicObject class. The TryGetMember method is called when a member of a dynamic class is requested
and no arguments are specified. The binder argument contains information about the referenced member,
and the result argument references the result returned for the specified member. The TryGetMember
method returns a Boolean value that returns true if the requested member exists; otherwise it returns
false .
// Implement the TryGetMember method of the DynamicObject class for dynamic member calls.
public override bool TryGetMember(GetMemberBinder binder,
out object result)
{
result = GetPropertyValue(binder.Name);
return result == null ? false : true;
}
' Implement the TryGetMember method of the DynamicObject class for dynamic member calls.
Public Overrides Function TryGetMember(ByVal binder As GetMemberBinder,
ByRef result As Object) As Boolean
result = GetPropertyValue(binder.Name)
Return If(result Is Nothing, False, True)
End Function
11. After the TryGetMember method, add the following code to override the TryInvokeMember method of the
DynamicObject class. The TryInvokeMember method is called when a member of a dynamic class is
requested with arguments. The binder argument contains information about the referenced member, and
the result argument references the result returned for the specified member. The args argument
contains an array of the arguments that are passed to the member. The TryInvokeMember method returns a
Boolean value that returns true if the requested member exists; otherwise it returns false .
The custom version of the TryInvokeMember method expects the first argument to be a value from the
StringSearchOption enum that you defined in a previous step. The TryInvokeMember method expects the
second argument to be a Boolean value. If one or both arguments are valid values, they are passed to the
GetPropertyValue method to retrieve the results.
try
{
if (args.Length > 0) { StringSearchOption = (StringSearchOption)args[0]; }
}
catch
{
throw new ArgumentException("StringSearchOption argument must be a StringSearchOption enum
value.");
}
try
{
if (args.Length > 1) { trimSpaces = (bool)args[1]; }
}
catch
{
throw new ArgumentException("trimSpaces argument must be a Boolean value.");
}
Try
If args.Length > 0 Then StringSearchOption = CType(args(0), StringSearchOption)
Catch
Throw New ArgumentException("StringSearchOption argument must be a StringSearchOption enum
value.")
End Try
Try
If args.Length > 1 Then trimSpaces = CType(args(1), Boolean)
Catch
Throw New ArgumentException("trimSpaces argument must be a Boolean value.")
End Try
3. Save the file and press CTRL+F5 to build and run the application.
using Microsoft.Scripting.Hosting;
using IronPython.Hosting;
Imports Microsoft.Scripting.Hosting
Imports IronPython.Hosting
7. In the Main method, add the following code to create a new Microsoft.Scripting.Hosting.ScriptRuntime
object to host the IronPython libraries. The ScriptRuntime object loads the IronPython library module
random.py.
// Set the current directory to the IronPython libraries.
System.IO.Directory.SetCurrentDirectory(
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) +
@"\IronPython 2.6 for .NET 4.0\Lib");
8. After the code to load the random.py module, add the following code to create an array of integers. The
array is passed to the shuffle method of the random.py module, which randomly sorts the values in the
array.
9. Save the file and press CTRL+F5 to build and run the application.
See also
System.Dynamic
System.Dynamic.DynamicObject
Using Type dynamic
Early and Late Binding
dynamic
Implementing Dynamic Interfaces (downloadable PDF from Microsoft TechNet)
Classes and structs (C# programming guide)
9/3/2020 • 6 minutes to read • Edit Online
Classes and structs are two of the basic constructs of the common type system in .NET. Each is essentially a
data structure that encapsulates a set of data and behaviors that belong together as a logical unit. The data and
behaviors are the members of the class or struct, and they include its methods, properties, and events, and so
on, as listed later in this topic.
A class or struct declaration is like a blueprint that is used to create instances or objects at run time. If you
define a class or struct called Person , Person is the name of the type. If you declare and initialize a variable p
of type Person , p is said to be an object or instance of Person . Multiple instances of the same Person type
can be created, and each instance can have different values in its properties and fields.
A class is a reference type. When an object of the class is created, the variable to which the object is assigned
holds only a reference to that memory. When the object reference is assigned to a new variable, the new
variable refers to the original object. Changes made through one variable are reflected in the other variable
because they both refer to the same data.
A struct is a value type. When a struct is created, the variable to which the struct is assigned holds the struct's
actual data. When the struct is assigned to a new variable, it is copied. The new variable and the original
variable therefore contain two separate copies of the same data. Changes made to one copy do not affect the
other copy.
In general, classes are used to model more complex behavior, or data that is intended to be modified after a
class object is created. Structs are best suited for small data structures that contain primarily data that is not
intended to be modified after the struct is created.
For more information, see Classes, Objects, and Structure types.
Example
In the following example, CustomClass in the ProgrammingGuide namespace has three members: an instance
constructor, a property named Number , and a method named Multiply . The Main method in the Program
class creates an instance (object) of CustomClass , and the object's method and property are accessed by using
dot notation.
using System;
namespace ProgrammingGuide
{
// Class definition.
public class CustomClass
{
// Class members.
//
// Property.
public int Number { get; set; }
// Method.
public int Multiply(int num)
{
return num * Number;
}
// Instance Constructor.
public CustomClass()
{
Number = 0;
}
}
// Another class definition that contains Main, the program entry point.
class Program
{
static void Main(string[] args)
{
// Create an object of type CustomClass.
CustomClass custClass = new CustomClass();
Encapsulation
Encapsulation is sometimes referred to as the first pillar or principle of object-oriented programming.
According to the principle of encapsulation, a class or struct can specify how accessible each of its members is
to code outside of the class or struct. Methods and variables that are not intended to be used from outside of
the class or assembly can be hidden to limit the potential for coding errors or malicious exploits.
For more information about classes, see Classes and Objects.
Members
All methods, fields, constants, properties, and events must be declared within a type; these are called the
members of the type. In C#, there are no global variables or methods as there are in some other languages.
Even a program's entry point, the Main method, must be declared within a class or struct. The following list
includes all the various kinds of members that may be declared in a class or struct.
Fields
Constants
Properties
Methods
Constructors
Events
Finalizers
Indexers
Operators
Nested Types
Accessibility
Some methods and properties are meant to be called or accessed from code outside your class or struct,
known as client code. Other methods and properties might be only for use in the class or struct itself. It is
important to limit the accessibility of your code so that only the intended client code can reach it. You specify
how accessible your types and their members are to client code by using the access modifiers public,
protected, internal, protected internal, private and private protected. The default accessibility is private . For
more information, see Access Modifiers.
Inheritance
Classes (but not structs) support the concept of inheritance. A class that derives from another class (the base
class) automatically contains all the public, protected, and internal members of the base class except its
constructors and finalizers. For more information, see Inheritance and Polymorphism.
Classes may be declared as abstract, which means that one or more of their methods have no implementation.
Although abstract classes cannot be instantiated directly, they can serve as base classes for other classes that
provide the missing implementation. Classes can also be declared as sealed to prevent other classes from
inheriting from them. For more information, see Abstract and Sealed Classes and Class Members.
Interfaces
Classes and structs can inherit multiple interfaces. To inherit from an interface means that the type implements
all the methods defined in the interface. For more information, see Interfaces.
Generic Types
Classes and structs can be defined with one or more type parameters. Client code supplies the type when it
creates an instance of the type. For example The List<T> class in the System.Collections.Generic namespace is
defined with one type parameter. Client code creates an instance of a List<string> or List<int> to specify
the type that the list will hold. For more information, see Generics.
Static Types
Classes (but not structs) can be declared as static. A static class can contain only static members and cannot be
instantiated with the new keyword. One copy of the class is loaded into memory when the program loads, and
its members are accessed through the class name. Both classes and structs can contain static members. For
more information, see Static Classes and Static Class Members.
Nested Types
A class or struct can be nested within another class or struct. For more information, see Nested Types.
Partial Types
You can define part of a class, struct or method in one code file and another part in a separate code file. For
more information, see Partial Classes and Methods.
Object Initializers
You can instantiate and initialize class or struct objects, and collections of objects, without explicitly calling their
constructor. For more information, see Object and Collection Initializers.
Anonymous Types
In situations where it is not convenient or necessary to create a named class, for example when you are
populating a list with data structures that you do not have to persist or pass to another method, you use
anonymous types. For more information, see Anonymous Types.
Extension Methods
You can "extend" a class without creating a derived class by creating a separate type whose methods can be
called as if they belonged to the original type. For more information, see Extension Methods.
Implicitly Typed Local Variables
Within a class or struct method, you can use implicit typing to instruct the compiler to determine the correct
type at compile time. For more information, see Implicitly Typed Local Variables.
C# Language Specification
For more information, see the C# Language Specification. The language specification is the definitive source
for C# syntax and usage.
See also
C# Programming Guide
Classes (C# Programming Guide)
4/23/2020 • 5 minutes to read • Edit Online
Reference types
A type that is defined as a class is a reference type. At run time, when you declare a variable of a reference type,
the variable contains the value null until you explicitly create an instance of the class by using the new operator,
or assign it an object of a compatible type that may have been created elsewhere, as shown in the following
example:
//Declaring another object of the same type, assigning it the value of the first object.
MyClass mc2 = mc;
When the object is created, enough memory is allocated on the managed heap for that specific object, and the
variable holds only a reference to the location of said object. Types on the managed heap require overhead both
when they are allocated and when they are reclaimed by the automatic memory management functionality of
the CLR, which is known as garbage collection. However, garbage collection is also highly optimized and in most
scenarios, it does not create a performance issue. For more information about garbage collection, see Automatic
memory management and garbage collection.
Declaring Classes
Classes are declared by using the class keyword followed by a unique identifier, as shown in the following
example:
The class keyword is preceded by the access level. Because public is used in this case, anyone can create
instances of this class. The name of the class follows the class keyword. The name of the class must be a valid
C# identifier name. The remainder of the definition is the class body, where the behavior and data are defined.
Fields, properties, methods, and events on a class are collectively referred to as class members.
Creating objects
Although they are sometimes used interchangeably, a class and an object are different things. A class defines a
type of object, but it is not an object itself. An object is a concrete entity based on a class, and is sometimes
referred to as an instance of a class.
Objects can be created by using the new keyword followed by the name of the class that the object will be
based on, like this:
Customer object2;
We don't recommend creating object references such as this one that don't refer to an object because trying to
access an object through such a reference will fail at run time. However, such a reference can be made to refer
to an object, either by creating a new object, or by assigning it to an existing object, such as this:
This code creates two object references that both refer to the same object. Therefore, any changes to the object
made through object3 are reflected in subsequent uses of object4 . Because objects that are based on classes
are referred to by reference, classes are known as reference types.
Class inheritance
Classes fully support inheritance, a fundamental characteristic of object-oriented programming. When you
create a class, you can inherit from any other interface or class that is not defined as sealed, and other classes
can inherit from your class and override class virtual methods.
Inheritance is accomplished by using a derivation, which means a class is declared by using a base class from
which it inherits data and behavior. A base class is specified by appending a colon and the name of the base
class following the derived class name, like this:
When a class declares a base class, it inherits all the members of the base class except the constructors. For
more information, see Inheritance.
Unlike C++, a class in C# can only directly inherit from one base class. However, because a base class may itself
inherit from another class, a class may indirectly inherit multiple base classes. Furthermore, a class can directly
implement more than one interface. For more information, see Interfaces.
A class can be declared abstract. An abstract class contains abstract methods that have a signature definition but
no implementation. Abstract classes cannot be instantiated. They can only be used through derived classes that
implement the abstract methods. By contrast, a sealed class does not allow other classes to derive from it. For
more information, see Abstract and Sealed Classes and Class Members.
Class definitions can be split between different source files. For more information, see Partial Classes and
Methods.
Example
The following example defines a public class that contains an auto-implemented property, a method, and a
special method called a constructor. For more information, see Properties, Methods, and Constructors topics.
The instances of the class are then instantiated with the new keyword.
using System;
C# Language Specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Programming Guide
Object-Oriented Programming
Polymorphism
Identifier names
Members
Methods
Constructors
Finalizers
Objects
Objects (C# Programming Guide)
9/3/2020 • 5 minutes to read • Edit Online
A class or struct definition is like a blueprint that specifies what the type can do. An object is basically a block of
memory that has been allocated and configured according to the blueprint. A program may create many objects
of the same class. Objects are also called instances, and they can be stored in either a named variable or in an
array or collection. Client code is the code that uses these variables to call the methods and access the public
properties of the object. In an object-oriented language such as C#, a typical program consists of multiple objects
interacting dynamically.
NOTE
Static types behave differently than what is described here. For more information, see Static Classes and Static Class
Members.
class Program
{
static void Main()
{
Person person1 = new Person("Leopold", 6);
Console.WriteLine("person1 Name = {0} Age = {1}", person1.Name, person1.Age);
Because structs are value types, a variable of a struct object holds a copy of the entire object. Instances of structs
can also be created by using the new operator, but this is not required, as shown in the following example:
public struct Person
{
public string Name;
public int Age;
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
The memory for both p1 and p2 is allocated on the thread stack. That memory is reclaimed along with the type
or method in which it is declared. This is one reason why structs are copied on assignment. By contrast, the
memory that is allocated for a class instance is automatically reclaimed (garbage collected) by the common
language runtime when all references to the object have gone out of scope. It is not possible to deterministically
destroy a class object like you can in C++. For more information about garbage collection in .NET, see Garbage
Collection.
NOTE
The allocation and deallocation of memory on the managed heap is highly optimized in the common language runtime. In
most cases there is no significant difference in the performance cost of allocating a class instance on the heap versus
allocating a struct instance on the stack.
if (p2.Equals(p1))
Console.WriteLine("p2 and p1 have the same values.");
The System.ValueType implementation of Equals uses reflection because it must be able to determine what the
fields are in any struct. When creating your own structs, override the Equals method to provide an efficient
equality algorithm that is specific to your type.
To determine whether the values of the fields in two class instances are equal, you might be able to use the
Equals method or the == operator. However, only use them if the class has overridden or overloaded them to
provide a custom definition of what "equality" means for objects of that type. The class might also implement
the IEquatable<T> interface or the IEqualityComparer<T> interface. Both interfaces provide methods that can
be used to test value equality. When designing your own classes that override Equals , make sure to follow the
guidelines stated in How to define value equality for a type and Object.Equals(Object).
Related Sections
For more information:
Classes
Constructors
Finalizers
Events
See also
C# Programming Guide
object
Inheritance
class
Structure types
new Operator
Common Type System
Inheritance (C# Programming Guide)
9/3/2020 • 7 minutes to read • Edit Online
Inheritance, together with encapsulation and polymorphism, is one of the three primary characteristics of
object-oriented programming. Inheritance enables you to create new classes that reuse, extend, and modify
the behavior defined in other classes. The class whose members are inherited is called the base class, and the
class that inherits those members is called the derived class. A derived class can have only one direct base
class. However, inheritance is transitive. If ClassC is derived from ClassB , and ClassB is derived from
ClassA , ClassC inherits the members declared in ClassB and ClassA .
NOTE
Structs do not support inheritance, but they can implement interfaces. For more information, see Interfaces.
Conceptually, a derived class is a specialization of the base class. For example, if you have a base class Animal ,
you might have one derived class that is named Mammal and another derived class that is named Reptile . A
Mammal is an Animal , and a Reptile is an Animal , but each derived class represents different specializations
of the base class.
Interface declarations may define a default implementation for its members. These implementations are
inherited by derived interfaces, and by classes that implement those interfaces. For more information on
default interface methods, see the article on interfaces in the language reference section.
When you define a class to derive from another class, the derived class implicitly gains all the members of the
base class, except for its constructors and finalizers. The derived class reuses the code in the base class
without having to reimplement it. You can add more members in the derived class. The derived class extends
the functionality of the base class.
The following illustration shows a class WorkItem that represents an item of work in some business process.
Like all classes, it derives from System.Object and inherits all its methods. WorkItem adds five members of its
own. These members include a constructor, because constructors aren't inherited. Class ChangeRequest
inherits from WorkItem and represents a particular kind of work item. ChangeRequest adds two more
members to the members that it inherits from WorkItem and from Object. It must add its own constructor,
and it also adds originalItemID . Property originalItemID enables the ChangeRequest instance to be
associated with the original WorkItem to which the change request applies.
The following example shows how the class relationships demonstrated in the previous illustration are
expressed in C#. The example also shows how WorkItem overrides the virtual method Object.ToString, and
how the ChangeRequest class inherits the WorkItem implementation of the method. The first block defines the
classes:
//Properties.
protected int ID { get; set; }
protected string Title { get; set; }
protected string Description { get; set; }
protected TimeSpan jobLength { get; set; }
// Method Update enables you to update the title and job length of an
// existing WorkItem object.
public void Update(string title, TimeSpan joblen)
{
this.Title = title;
this.jobLength = joblen;
}
This next block shows how to use the base and derived classes:
Interfaces
An interface is a reference type that defines a set of members. All classes and structs that implement that
interface must implement that set of members. An interface may define a default implementation for any or
all of these members. A class can implement multiple interfaces even though it can derive from only a single
direct base class.
Interfaces are used to define specific capabilities for classes that don't necessarily have an "is a" relationship.
For example, the System.IEquatable<T> interface can be implemented by any class or struct to determine
whether two objects of the type are equivalent (however the type defines equivalence). IEquatable<T> doesn't
imply the same kind of "is a" relationship that exists between a base class and a derived class (for example, a
Mammal is an Animal ). For more information, see Interfaces.
See also
C# Programming Guide
Classes and Structs
class
Polymorphism (C# Programming Guide)
9/3/2020 • 7 minutes to read • Edit Online
Polymorphism is often referred to as the third pillar of object-oriented programming, after encapsulation and
inheritance. Polymorphism is a Greek word that means "many-shaped" and it has two distinct aspects:
At run time, objects of a derived class may be treated as objects of a base class in places such as method
parameters and collections or arrays. When this polymorphism occurs, the object's declared type is no longer
identical to its run-time type.
Base classes may define and implement virtual methods, and derived classes can override them, which means
they provide their own definition and implementation. At run-time, when client code calls the method, the
CLR looks up the run-time type of the object, and invokes that override of the virtual method. In your source
code you can call a method on a base class, and cause a derived class's version of the method to be executed.
Virtual methods enable you to work with groups of related objects in a uniform way. For example, suppose you
have a drawing application that enables a user to create various kinds of shapes on a drawing surface. You do not
know at compile time which specific types of shapes the user will create. However, the application has to keep
track of all the various types of shapes that are created, and it has to update them in response to user mouse
actions. You can use polymorphism to solve this problem in two basic steps:
1. Create a class hierarchy in which each specific shape class derives from a common base class.
2. Use a virtual method to invoke the appropriate method on any derived class through a single call to the base
class method.
First, create a base class called Shape , and derived classes such as Rectangle , Circle , and Triangle . Give the
Shape class a virtual method called Draw , and override it in each derived class to draw the particular shape that
the class represents. Create a List<Shape> object and add a Circle , Triangle , and Rectangle to it.
public class Shape
{
// A few example members
public int X { get; private set; }
public int Y { get; private set; }
public int Height { get; set; }
public int Width { get; set; }
// Virtual method
public virtual void Draw()
{
Console.WriteLine("Performing base class drawing tasks");
}
}
To update the drawing surface, use a foreach loop to iterate through the list and call the Draw method on each
Shape object in the list. Even though each object in the list has a declared type of Shape , it's the run-time type
(the overridden version of the method in each derived class) that will be invoked.
// Polymorphism at work #1: a Rectangle, Triangle and Circle
// can all be used whereever a Shape is expected. No cast is
// required because an implicit conversion exists from a derived
// class to its base class.
var shapes = new List<Shape>
{
new Rectangle(),
new Triangle(),
new Circle()
};
In C#, every type is polymorphic because all types, including user-defined types, inherit from Object.
Polymorphism overview
Virtual members
When a derived class inherits from a base class, it gains all the methods, fields, properties, and events of the base
class. The designer of the derived class has different choices for the behavior of virtual methods:
The derived class may override virtual members in the base class, defining new behavior.
The derived class inherit the closest base class method without overriding it, preserving the existing behavior
but enabling further derived classes to override the method.
The derived class may define new non-virtual implementation of those members that hide the base class
implementations.
A derived class can override a base class member only if the base class member is declared as virtual or abstract.
The derived member must use the override keyword to explicitly indicate that the method is intended to
participate in virtual invocation. The following code provides an example:
BaseClass A = (BaseClass)B;
A.DoWork(); // Also calls the new method.
Virtual methods and properties enable derived classes to extend a base class without needing to use the base
class implementation of a method. For more information, see Versioning with the Override and New Keywords.
An interface provides another way to define a method or set of methods whose implementation is left to derived
classes. For more information, see Interfaces.
Hide base class members with new members
If you want your derived class to have a member with the same name as a member in a base class, you can use
the new keyword to hide the base class member. The new keyword is put before the return type of a class
member that is being replaced. The following code provides an example:
Hidden base class members may be accessed from client code by casting the instance of the derived class to an
instance of the base class. For example:
BaseClass A = (BaseClass)B;
A.DoWork(); // Calls the old method.
A derived class can stop virtual inheritance by declaring an override as sealed. Stopping inheritance requires
putting the sealed keyword before the override keyword in the class member declaration. The following code
provides an example:
public class C : B
{
public sealed override void DoWork() { }
}
In the previous example, the method DoWork is no longer virtual to any class derived from C . It's still virtual for
instances of C , even if they're cast to type B or type A . Sealed methods can be replaced by derived classes by
using the new keyword, as the following example shows:
public class D : C
{
public new void DoWork() { }
}
In this case, if DoWork is called on D using a variable of type D , the new DoWork is called. If a variable of type
C , B , or A is used to access an instance of D , a call to DoWork will follow the rules of virtual inheritance,
routing those calls to the implementation of DoWork on class C .
Access base class virtual members from derived classes
A derived class that has replaced or overridden a method or property can still access the method or property on
the base class using the base keyword. The following code provides an example:
In this section
Versioning with the Override and New Keywords
Knowing When to Use Override and New Keywords
How to override the ToString method
See also
C# Programming Guide
Inheritance
Abstract and Sealed Classes and Class Members
Methods
Events
Properties
Indexers
Types
Versioning with the Override and New Keywords (C#
Programming Guide)
9/3/2020 • 5 minutes to read • Edit Online
The C# language is designed so that versioning between base and derived classes in different libraries can evolve
and maintain backward compatibility. This means, for example, that the introduction of a new member in a base
class with the same name as a member in a derived class is completely supported by C# and does not lead to
unexpected behavior. It also means that a class must explicitly state whether a method is intended to override an
inherited method, or whether a method is a new method that hides a similarly named inherited method.
In C#, derived classes can contain methods with the same name as base class methods.
If the method in the derived class is not preceded by new or override keywords, the compiler will issue a
warning and the method will behave as if the new keyword were present.
If the method in the derived class is preceded with the new keyword, the method is defined as being
independent of the method in the base class.
If the method in the derived class is preceded with the override keyword, objects of the derived class will
call that method instead of the base class method.
In order to apply the override keyword to the method in the derived class, the base class method must be
defined virtual.
The base class method can be called from within the derived class using the base keyword.
The override , virtual , and new keywords can also be applied to properties, indexers, and events.
By default, C# methods are not virtual. If a method is declared as virtual, any class inheriting the method can
implement its own version. To make a method virtual, the virtual modifier is used in the method declaration of
the base class. The derived class can then override the base virtual method by using the override keyword or
hide the virtual method in the base class by using the new keyword. If neither the override keyword nor the
new keyword is specified, the compiler will issue a warning and the method in the derived class will hide the
method in the base class.
To demonstrate this in practice, assume for a moment that Company A has created a class named GraphicsClass ,
which your program uses. The following is GraphicsClass :
class GraphicsClass
{
public virtual void DrawLine() { }
public virtual void DrawPoint() { }
}
Your company uses this class, and you use it to derive your own class, adding a new method:
Your application is used without problems, until Company A releases a new version of GraphicsClass , which
resembles the following code:
class GraphicsClass
{
public virtual void DrawLine() { }
public virtual void DrawPoint() { }
public virtual void DrawRectangle() { }
}
The new version of GraphicsClass now contains a method named DrawRectangle . Initially, nothing occurs. The
new version is still binary compatible with the old version. Any software that you have deployed will continue to
work, even if the new class is installed on those computer systems. Any existing calls to the method
DrawRectangle will continue to reference your version, in your derived class.
However, as soon as you recompile your application by using the new version of GraphicsClass , you will receive a
warning from the compiler, CS0108. This warning informs you that you have to consider how you want your
DrawRectangle method to behave in your application.
If you want your method to override the new base class method, use the override keyword:
The override keyword makes sure that any objects derived from YourDerivedGraphicsClass will use the derived
class version of DrawRectangle . Objects derived from YourDerivedGraphicsClass can still access the base class
version of DrawRectangle by using the base keyword:
base.DrawRectangle();
If you do not want your method to override the new base class method, the following considerations apply. To
avoid confusion between the two methods, you can rename your method. This can be time-consuming and error-
prone, and just not practical in some cases. However, if your project is relatively small, you can use Visual Studio's
Refactoring options to rename the method. For more information, see Refactoring Classes and Types (Class
Designer).
Alternatively, you can prevent the warning by using the keyword new in your derived class definition:
Using the new keyword tells the compiler that your definition hides the definition that is contained in the base
class. This is the default behavior.
When DoWork is called on an instance of Derived , the C# compiler will first try to make the call compatible with
the versions of DoWork declared originally on Derived . Override methods are not considered as declared on a
class, they are new implementations of a method declared on a base class. Only if the C# compiler cannot match
the method call to an original method on Derived will it try to match the call to an overridden method with the
same name and compatible parameters. For example:
int val = 5;
Derived d = new Derived();
d.DoWork(val); // Calls DoWork(double).
Because the variable val can be converted to a double implicitly, the C# compiler calls DoWork(double) instead of
DoWork(int) . There are two ways to avoid this. First, avoid declaring new methods with the same name as virtual
methods. Second, you can instruct the C# compiler to call the virtual method by making it search the base class
method list by casting the instance of Derived to Base . Because the method is virtual, the implementation of
DoWork(int) on Derived will be called. For example:
For more examples of new and override , see Knowing When to Use Override and New Keywords.
See also
C# Programming Guide
Classes and Structs
Methods
Inheritance
Knowing When to Use Override and New Keywords
(C# Programming Guide)
9/3/2020 • 10 minutes to read • Edit Online
In C#, a method in a derived class can have the same name as a method in the base class. You can specify how the
methods interact by using the new and override keywords. The override modifier extends the base class
virtual method, and the new modifier hides an accessible base class method. The difference is illustrated in the
examples in this topic.
In a console application, declare the following two classes, BaseClass and DerivedClass . DerivedClass inherits
from BaseClass .
class BaseClass
{
public void Method1()
{
Console.WriteLine("Base - Method1");
}
}
bc.Method1();
dc.Method1();
dc.Method2();
bcdc.Method1();
}
// Output:
// Base - Method1
// Base - Method1
// Derived - Method2
// Base - Method1
}
Next, add the following Method2 method to BaseClass . The signature of this method matches the signature of the
Method2 method in DerivedClass .
Because BaseClass now has a Method2 method, a second calling statement can be added for BaseClass variables
bc and bcdc , as shown in the following code.
bc.Method1();
bc.Method2();
dc.Method1();
dc.Method2();
bcdc.Method1();
bcdc.Method2();
When you build the project, you see that the addition of the Method2 method in BaseClass causes a warning. The
warning says that the Method2 method in DerivedClass hides the Method2 method in BaseClass . You are advised
to use the new keyword in the Method2 definition if you intend to cause that result. Alternatively, you could
rename one of the Method2 methods to resolve the warning, but that is not always practical.
Before adding new , run the program to see the output produced by the additional calling statements. The
following results are displayed.
// Output:
// Base - Method1
// Base - Method2
// Base - Method1
// Derived - Method2
// Base - Method1
// Base - Method2
The new keyword preserves the relationships that produce that output, but it suppresses the warning. The
variables that have type BaseClass continue to access the members of BaseClass , and the variable that has type
DerivedClass continues to access members in DerivedClass first, and then to consider members inherited from
BaseClass .
To suppress the warning, add the new modifier to the definition of Method2 in DerivedClass , as shown in the
following code. The modifier can be added before or after public .
Run the program again to verify that the output has not changed. Also verify that the warning no longer appears.
By using new , you are asserting that you are aware that the member that it modifies hides a member that is
inherited from the base class. For more information about name hiding through inheritance, see new Modifier.
To contrast this behavior to the effects of using override , add the following method to DerivedClass . The
override modifier can be added before or after public .
Add the virtual modifier to the definition of Method1 in BaseClass . The virtual modifier can be added before
or after public .
Run the project again. Notice especially the last two lines of the following output.
// Output:
// Base - Method1
// Base - Method2
// Derived - Method1
// Derived - Method2
// Derived - Method1
// Base - Method2
The use of the override modifier enables bcdc to access the Method1 method that is defined in DerivedClass .
Typically, that is the desired behavior in inheritance hierarchies. You want objects that have values that are created
from the derived class to use the methods that are defined in the derived class. You achieve that behavior by using
override to extend the base class method.
namespace OverrideAndNew
{
class Program
{
static void Main(string[] args)
{
BaseClass bc = new BaseClass();
DerivedClass dc = new DerivedClass();
BaseClass bcdc = new DerivedClass();
// The following two calls do what you would expect. They call
// the methods that are defined in BaseClass.
bc.Method1();
bc.Method2();
// Output:
// Base - Method1
// Base - Method2
// The following two calls do what you would expect. They call
// the methods that are defined in DerivedClass.
dc.Method1();
dc.Method2();
// Output:
// Derived - Method1
// Derived - Method2
class BaseClass
{
public virtual void Method1()
{
Console.WriteLine("Base - Method1");
}
// Define the base class, Car. The class defines two methods,
// DescribeCar and ShowDetails. DescribeCar calls ShowDetails, and each derived
// class also defines a ShowDetails method. The example tests which version of
// ShowDetails is selected, the base class method or the derived class method.
class Car
{
public void DescribeCar()
{
System.Console.WriteLine("Four wheels and an engine.");
ShowDetails();
}
The example tests which version of ShowDetails is called. The following method, TestCars1 , declares an instance
of each class, and then calls DescribeCar on each instance.
public static void TestCars1()
{
System.Console.WriteLine("\nTestCars1");
System.Console.WriteLine("----------");
// Notice the output from this test case. The new modifier is
// used in the definition of ShowDetails in the ConvertibleCar
// class.
TestCars1 produces the following output. Notice especially the results for car2 , which probably are not what
you expected. The type of the object is ConvertibleCar , but DescribeCar does not access the version of
ShowDetails that is defined in the ConvertibleCar class because that method is declared with the new modifier,
not the override modifier. As a result, a ConvertibleCar object displays the same description as a Car object.
Contrast the results for car3 , which is a Minivan object. In this case, the ShowDetails method that is declared in
the Minivan class overrides the ShowDetails method that is declared in the Car class, and the description that is
displayed describes a minivan.
// TestCars1
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------
TestCars2 creates a list of objects that have type Car . The values of the objects are instantiated from the Car ,
ConvertibleCar , and Minivan classes. DescribeCar is called on each element of the list. The following code shows
the definition of TestCars2 .
// TestCars2
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------
Methods TestCars3 and TestCars4 complete the example. These methods call ShowDetails directly, first from
objects declared to have type ConvertibleCar and Minivan ( TestCars3 ), then from objects declared to have type
Car ( TestCars4 ). The following code defines these two methods.
The methods produce the following output, which corresponds to the results from the first example in this topic.
// TestCars3
// ----------
// A roof that opens up.
// Carries seven people.
// TestCars4
// ----------
// Standard transportation.
// Carries seven people.
The following code shows the complete project and its output.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OverrideAndNew2
namespace OverrideAndNew2
{
class Program
{
static void Main(string[] args)
{
// Declare objects of the derived classes and test which version
// of ShowDetails is run, base or derived.
TestCars1();
// Notice the output from this test case. The new modifier is
// used in the definition of ShowDetails in the ConvertibleCar
// class.
ConvertibleCar car2 = new ConvertibleCar();
car2.DescribeCar();
System.Console.WriteLine("----------");
// Define the base class, Car. The class defines two virtual methods,
// DescribeCar and ShowDetails. DescribeCar calls ShowDetails, and each derived
// class also defines a ShowDetails method. The example tests which version of
// ShowDetails is used, the base class method or the derived class method.
class Car
{
public virtual void DescribeCar()
{
System.Console.WriteLine("Four wheels and an engine.");
ShowDetails();
}
See also
C# Programming Guide
Classes and Structs
Versioning with the Override and New Keywords
base
abstract
How to override the ToString method (C#
Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
Every class or struct in C# implicitly inherits the Object class. Therefore, every object in C# gets the ToString
method, which returns a string representation of that object. For example, all variables of type int have a
ToString method, which enables them to return their contents as a string:
int x = 42;
string strx = x.ToString();
Console.WriteLine(strx);
// Output:
// 42
When you create a custom class or struct, you should override the ToString method in order to provide information
about your type to client code.
For information about how to use format strings and other types of custom formatting with the ToString method,
see Formatting Types.
IMPORTANT
When you decide what information to provide through this method, consider whether your class or struct will ever be used
by untrusted code. Be careful to ensure that you do not provide any information that could be exploited by malicious code.
class Person
{
public string Name { get; set; }
public int Age { get; set; }
You can test the ToString method as shown in the following code example:
Person person = new Person { Name = "John", Age = 12 };
Console.WriteLine(person);
// Output:
// Person: John 12
See also
IFormattable
C# Programming Guide
Classes and Structs
Strings
string
override
virtual
Formatting Types
Members (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
Classes and structs have members that represent their data and behavior. A class's members include all the
members declared in the class, along with all members (except constructors and finalizers) declared in all classes
in its inheritance hierarchy. Private members in base classes are inherited but are not accessible from derived
classes.
The following table lists the kinds of members a class or struct may contain:
M EM B ER DESC RIP T IO N
Constants Constants are fields whose value is set at compile time and
cannot be changed.
Methods Methods define the actions that a class can perform. Methods
can take parameters that provide input data, and can return
output data through parameters. Methods can also return a
value directly, without using a parameter.
Constructors Constructors are methods that are called when the object is
first created. They are often used to initialize the data of an
object.
Finalizers Finalizers are used very rarely in C#. They are methods that
are called by the runtime execution engine when the object is
about to be removed from memory. They are generally used
to make sure that any resources which must be released are
handled appropriately.
M EM B ER DESC RIP T IO N
Nested Types Nested types are types declared within another type. Nested
types are often used to describe objects that are used only by
the types that contain them.
See also
C# Programming Guide
Classes
Abstract and Sealed Classes and Class Members
(C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
The abstract keyword enables you to create classes and class members that are incomplete and must be
implemented in a derived class.
The sealed keyword enables you to prevent the inheritance of a class or certain class members that were
previously marked virtual.
An abstract class cannot be instantiated. The purpose of an abstract class is to provide a common definition of a
base class that multiple derived classes can share. For example, a class library may define an abstract class that
is used as a parameter to many of its functions, and require programmers using that library to provide their
own implementation of the class by creating a derived class.
Abstract classes may also define abstract methods. This is accomplished by adding the keyword abstract
before the return type of the method. For example:
Abstract methods have no implementation, so the method definition is followed by a semicolon instead of a
normal method block. Derived classes of the abstract class must implement all abstract methods. When an
abstract class inherits a virtual method from a base class, the abstract class can override the virtual method with
an abstract method. For example:
// compile with: -target:library
public class D
{
public virtual void DoWork(int i)
{
// Original implementation.
}
}
public class F : E
{
public override void DoWork(int i)
{
// New implementation.
}
}
If a virtual method is declared abstract , it is still virtual to any class inheriting from the abstract class. A class
inheriting an abstract method cannot access the original implementation of the method—in the previous
example, DoWork on class F cannot call DoWork on class D. In this way, an abstract class can force derived
classes to provide new method implementations for virtual methods.
A sealed class cannot be used as a base class. For this reason, it cannot also be an abstract class. Sealed classes
prevent derivation. Because they can never be used as a base class, some run-time optimizations can make
calling sealed class members slightly faster.
A method, indexer, property, or event, on a derived class that is overriding a virtual member of the base class
can declare that member as sealed. This negates the virtual aspect of the member for any further derived class.
This is accomplished by putting the sealed keyword before the override keyword in the class member
declaration. For example:
public class D : C
{
public sealed override void DoWork() { }
}
See also
C# Programming Guide
Classes and Structs
Inheritance
Methods
Fields
How to define abstract properties
Static Classes and Static Class Members (C#
Programming Guide)
9/3/2020 • 5 minutes to read • Edit Online
A static class is basically the same as a non-static class, but there is one difference: a static class cannot be
instantiated. In other words, you cannot use the new operator to create a variable of the class type. Because there
is no instance variable, you access the members of a static class by using the class name itself. For example, if you
have a static class that is named UtilityClass that has a public static method named MethodA , you call the
method as shown in the following example:
UtilityClass.MethodA();
A static class can be used as a convenient container for sets of methods that just operate on input parameters
and do not have to get or set any internal instance fields. For example, in the .NET Class Library, the static
System.Math class contains methods that perform mathematical operations, without any requirement to store or
retrieve data that is unique to a particular instance of the Math class. That is, you apply the members of the class
by specifying the class name and the method name, as shown in the following example.
// Output:
// 3.14
// -4
// 3
As is the case with all class types, the type information for a static class is loaded by the .NET runtime when the
program that references the class is loaded. The program cannot specify exactly when the class is loaded.
However, it is guaranteed to be loaded and to have its fields initialized and its static constructor called before the
class is referenced for the first time in your program. A static constructor is only called one time, and a static class
remains in memory for the lifetime of the application domain in which your program resides.
NOTE
To create a non-static class that allows only one instance of itself to be created, see Implementing Singleton in C#.
Example
Here is an example of a static class that contains two methods that convert temperature from Celsius to
Fahrenheit and from Fahrenheit to Celsius:
return fahrenheit;
}
return celsius;
}
}
class TestTemperatureConverter
{
static void Main()
{
Console.WriteLine("Please select the convertor direction");
Console.WriteLine("1. From Celsius to Fahrenheit.");
Console.WriteLine("2. From Fahrenheit to Celsius.");
Console.Write(":");
switch (selection)
{
case "1":
Console.Write("Please enter the Celsius temperature: ");
F = TemperatureConverter.CelsiusToFahrenheit(Console.ReadLine());
Console.WriteLine("Temperature in Fahrenheit: {0:F2}", F);
break;
case "2":
Console.Write("Please enter the Fahrenheit temperature: ");
C = TemperatureConverter.FahrenheitToCelsius(Console.ReadLine());
Console.WriteLine("Temperature in Celsius: {0:F2}", C);
break;
default:
Console.WriteLine("Please select a convertor.");
break;
break;
}
Static Members
A non-static class can contain static methods, fields, properties, or events. The static member is callable on a class
even when no instance of the class has been created. The static member is always accessed by the class name,
not the instance name. Only one copy of a static member exists, regardless of how many instances of the class
are created. Static methods and properties cannot access non-static fields and events in their containing type,
and they cannot access an instance variable of any object unless it's explicitly passed in a method parameter.
It is more typical to declare a non-static class with some static members, than to declare an entire class as static.
Two common uses of static fields are to keep a count of the number of objects that have been instantiated, or to
store a value that must be shared among all instances.
Static methods can be overloaded but not overridden, because they belong to the class, and not to any instance
of the class.
Although a field cannot be declared as static const , a const field is essentially static in its behavior. It belongs to
the type, not to instances of the type. Therefore, const fields can be accessed by using the same
ClassName.MemberName notation that's used for static fields. No object instance is required.
C# does not support static local variables (that is, variables that are declared in method scope).
You declare static class members by using the static keyword before the return type of the member, as shown
in the following example:
Static members are initialized before the static member is accessed for the first time and before the static
constructor, if there is one, is called. To access a static class member, use the name of the class instead of a
variable name to specify the location of the member, as shown in the following example:
Automobile.Drive();
int i = Automobile.NumberOfWheels;
If your class contains static fields, provide a static constructor that initializes them when the class is loaded.
A call to a static method generates a call instruction in Microsoft intermediate language (MSIL), whereas a call to
an instance method generates a callvirt instruction, which also checks for null object references. However,
most of the time the performance difference between the two is not significant.
C# Language Specification
For more information, see Static classes and Static and instance members in the C# Language Specification. The
language specification is the definitive source for C# syntax and usage.
See also
C# Programming Guide
static
Classes
class
Static Constructors
Instance Constructors
Access Modifiers (C# Programming Guide)
9/3/2020 • 4 minutes to read • Edit Online
All types and type members have an accessibility level. The accessibility level controls whether they can be used
from other code in your assembly or other assemblies. Use the following access modifiers to specify the
accessibility of a type or member when you declare it:
public: The type or member can be accessed by any other code in the same assembly or another assembly
that references it.
private: The type or member can be accessed only by code in the same class or struct .
protected: The type or member can be accessed only by code in the same class , or in a class that is
derived from that class .
internal: The type or member can be accessed by any code in the same assembly, but not from another
assembly.
protected internal: The type or member can be accessed by any code in the assembly in which it's declared,
or from within a derived class in another assembly.
private protected: The type or member can be accessed only within its declaring assembly, by code in the
same class or in a type that is derived from that class .
The following examples demonstrate how to specify access modifiers on a type and member:
Not all access modifiers are valid for all types or members in all contexts. In some cases, the accessibility of a
type member is constrained by the accessibility of its containing type.
User-defined operators must always be declared as public and static . For more information, see Operator
overloading.
Finalizers can't have accessibility modifiers.
To set the access level for a class or struct member, add the appropriate keyword to the member declaration,
as shown in the following example.
// public class:
public class Tricycle
{
// protected method:
protected void Pedal() { }
// private field:
private int wheels = 3;
Other types
Interfaces declared directly within a namespace can be public or internal and, just like classes and structs,
interfaces default to internal access. Interface members are public by default because the purpose of an
interface is to enable other types to access a class or struct. Interface member declarations may include any
access modifier. This is most useful for static methods to provide common implementations needed by all
implementors of a class.
Enumeration members are always public , and no access modifiers can be applied.
Delegates behave like classes and structs. By default, they have internal access when declared directly within a
namespace, and private access when nested.
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Programming Guide
Classes and Structs
Interfaces
private
public
internal
protected
protected internal
private protected
class
struct
interface
Fields (C# Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
A field is a variable of any type that is declared directly in a class or struct. Fields are members of their containing
type.
A class or struct may have instance fields, static fields, or both. Instance fields are specific to an instance of a type.
If you have a class T, with an instance field F, you can create two objects of type T, and modify the value of F in each
object without affecting the value in the other object. By contrast, a static field belongs to the class itself, and is
shared among all instances of that class. You can access the static field only by using the class name. If you access
the static field by an instance name, you get CS0176 compile-time error.
Generally, you should use fields only for variables that have private or protected accessibility. Data that your class
exposes to client code should be provided through methods, properties, and indexers. By using these constructs
for indirect access to internal fields, you can guard against invalid input values. A private field that stores the data
exposed by a public property is called a backing store or backing field.
Fields typically store the data that must be accessible to more than one class method and must be stored for
longer than the lifetime of any single method. For example, a class that represents a calendar date might have
three integer fields: one for the month, one for the day, and one for the year. Variables that are not used outside
the scope of a single method should be declared as local variables within the method body itself.
Fields are declared in the class block by specifying the access level of the field, followed by the type of the field,
followed by the name of the field. For example:
public class CalendarEntry
{
// private field
private DateTime date;
To access a field in an object, add a period after the object name, followed by the name of the field, as in
objectname.fieldname . For example:
CalendarEntry birthday = new CalendarEntry();
birthday.day = "Saturday";
A field can be given an initial value by using the assignment operator when the field is declared. To automatically
assign the day field to "Monday" , for example, you would declare day as in the following example:
Fields are initialized immediately before the constructor for the object instance is called. If the constructor assigns
the value of a field, it will overwrite any value given during field declaration. For more information, see Using
Constructors.
NOTE
A field initializer cannot refer to other instance fields.
Fields can be marked as public, private, protected, internal, protected internal, or private protected. These access
modifiers define how users of the class can access the fields. For more information, see Access Modifiers.
A field can optionally be declared static. This makes the field available to callers at any time, even if no instance of
the class exists. For more information, see Static Classes and Static Class Members.
A field can be declared readonly. A read-only field can only be assigned a value during initialization or in a
constructor. A static readonly field is very similar to a constant, except that the C# compiler does not have access
to the value of a static read-only field at compile time, only at run time. For more information, see Constants.
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for C#
syntax and usage.
See also
C# Programming Guide
Classes and Structs
Using Constructors
Inheritance
Access Modifiers
Abstract and Sealed Classes and Class Members
Constants (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
Constants are immutable values which are known at compile time and do not change for the life of the program.
Constants are declared with the const modifier. Only the C# built-in types (excluding System.Object) may be
declared as const . User-defined types, including classes, structs, and arrays, cannot be const . Use the readonly
modifier to create a class, struct, or array that is initialized one time at runtime (for example in a constructor) and
thereafter cannot be changed.
C# does not support const methods, properties, or events.
The enum type enables you to define named constants for integral built-in types (for example int , uint , long ,
and so on). For more information, see enum.
Constants must be initialized as they are declared. For example:
class Calendar1
{
public const int Months = 12;
}
In this example, the constant Months is always 12, and it cannot be changed even by the class itself. In fact, when
the compiler encounters a constant identifier in C# source code (for example, Months ), it substitutes the literal
value directly into the intermediate language (IL) code that it produces. Because there is no variable address
associated with a constant at run time, const fields cannot be passed by reference and cannot appear as an l-
value in an expression.
NOTE
Use caution when you refer to constant values defined in other code such as DLLs. If a new version of the DLL defines a new
value for the constant, your program will still hold the old literal value until it is recompiled against the new version.
Multiple constants of the same type can be declared at the same time, for example:
class Calendar2
{
public const int Months = 12, Weeks = 52, Days = 365;
}
The expression that is used to initialize a constant can refer to another constant if it does not create a circular
reference. For example:
class Calendar3
{
public const int Months = 12;
public const int Weeks = 52;
public const int Days = 365;
C# Language Specification
For more information, see the C# Language Specification. The language specification is the definitive source for C#
syntax and usage.
See also
C# Programming Guide
Classes and Structs
Properties
Types
readonly
Immutability in C# Part One: Kinds of Immutability
How to define abstract properties (C# Programming
Guide)
9/3/2020 • 2 minutes to read • Edit Online
The following example shows how to define abstract properties. An abstract property declaration does not provide
an implementation of the property accessors -- it declares that the class supports properties, but leaves the
accessor implementation to derived classes. The following example demonstrates how to implement the abstract
properties inherited from a base class.
This sample consists of three files, each of which is compiled individually and its resulting assembly is referenced
by the next compilation:
abstractshape.cs: the Shape class that contains an abstract Area property.
shapes.cs: The subclasses of the Shape class.
shapetest.cs: A test program to display the areas of some Shape -derived objects.
To compile the example, use the following command:
csc abstractshape.cs shapes.cs shapetest.cs
Example
This file declares the Shape class that contains the Area property of the type double .
// compile with: csc -target:library abstractshape.cs
public abstract class Shape
{
private string name;
public Shape(string s)
{
// calling the set accessor of the Id property.
Id = s;
}
public string Id
{
get
{
return name;
}
set
{
name = value;
}
}
Modifiers on the property are placed on the property declaration itself. For example:
When declaring an abstract property (such as Area in this example), you simply indicate what property
accessors are available, but do not implement them. In this example, only a get accessor is available, so the
property is read-only.
Example
The following code shows three subclasses of Shape and how they override the Area property to provide their
own implementation.
// compile with: csc -target:library -reference:abstractshape.dll shapes.cs
public class Square : Shape
{
private int side;
Example
The following code shows a test program that creates a number of Shape -derived objects and prints out their
areas.
System.Console.WriteLine("Shapes Collection");
foreach (Shape s in shapes)
{
System.Console.WriteLine(s);
}
}
}
/* Output:
Shapes Collection
Square #1 Area = 25.00
Circle #1 Area = 28.27
Rectangle #1 Area = 20.00
*/
See also
C# Programming Guide
Classes and Structs
Abstract and Sealed Classes and Class Members
Properties
How to define constants in C#
9/3/2020 • 2 minutes to read • Edit Online
Constants are fields whose values are set at compile time and can never be changed. Use constants to provide
meaningful names instead of numeric literals ("magic numbers") for special values.
NOTE
In C# the #define preprocessor directive cannot be used to define constants in the way that is typically used in C and C++.
To define constant values of integral types ( int , byte , and so on) use an enumerated type. For more information,
see enum.
To define non-integral constants, one approach is to group them in a single static class named Constants . This will
require that all references to the constants be prefaced with the class name, as shown in the following example.
Example
static class Constants
{
public const double Pi = 3.14159;
public const int SpeedOfLight = 300000; // km per sec.
}
class Program
{
static void Main()
{
double radius = 5.3;
double area = Constants.Pi * (radius * radius);
int secsFromSun = 149476000 / Constants.SpeedOfLight; // in km
}
}
The use of the class name qualifier helps ensure that you and others who use the constant understand that it is
constant and cannot be modified.
See also
Classes and Structs
Properties (C# Programming Guide)
9/3/2020 • 4 minutes to read • Edit Online
A property is a member that provides a flexible mechanism to read, write, or compute the value of a private
field. Properties can be used as if they are public data members, but they are actually special methods called
accessors. This enables data to be accessed easily and still helps promote the safety and flexibility of
methods.
Properties overview
Properties enable a class to expose a public way of getting and setting values, while hiding
implementation or verification code.
A get property accessor is used to return the property value, and a set property accessor is used to
assign a new value. These accessors can have different access levels. For more information, see
Restricting Accessor Accessibility.
The value keyword is used to define the value being assigned by the set accessor.
Properties can be read-write (they have both a get and a set accessor), read-only (they have a get
accessor but no set accessor), or write-only (they have a set accessor, but no get accessor). Write-
only properties are rare and are most commonly used to restrict access to sensitive data.
Simple properties that require no custom accessor code can be implemented either as expression
body definitions or as auto-implemented properties.
class TimePeriod
{
private double _seconds;
class Program
{
static void Main()
{
TimePeriod t = new TimePeriod();
// The property assignment causes the 'set' accessor to be called.
t.Hours = 24;
Starting with C# 7.0, both the get and the set accessor can be implemented as expression-bodied
members. In this case, the get and set keywords must be present. The following example illustrates the
use of expression body definitions for both accessors. Note that the return keyword is not used with the
get accessor.
using System;
class Program
{
static void Main(string[] args)
{
var item = new SaleItem("Shoes", 19.95m);
Console.WriteLine($"{item.Name}: sells for {item.Price:C2}");
}
}
// The example displays output like the following:
// Shoes: sells for $19.95
Auto-implemented properties
In some cases, property get and set accessors just assign a value to or retrieve a value from a backing
field without including any additional logic. By using auto-implemented properties, you can simplify your
code while having the C# compiler transparently provide the backing field for you.
If a property has both a get and a set accessor, both must be auto-implemented. You define an auto-
implemented property by using the get and set keywords without providing any implementation. The
following example repeats the previous one, except that Name and Price are auto-implemented properties.
Note that the example also removes the parameterized constructor, so that SaleItem objects are now
initialized with a call to the parameterless constructor and an object initializer.
using System;
class Program
{
static void Main(string[] args)
{
var item = new SaleItem{ Name = "Shoes", Price = 19.95m };
Console.WriteLine($"{item.Name}: sells for {item.Price:C2}");
}
}
// The example displays output like the following:
// Shoes: sells for $19.95
Related sections
Using Properties
Interface Properties
Comparison Between Properties and Indexers
Restricting Accessor Accessibility
Auto-Implemented Properties
C# Language Specification
For more information, see Properties in the C# Language Specification. The language specification is the
definitive source for C# syntax and usage.
See also
C# Programming Guide
Using Properties
Indexers
get keyword
set keyword
Using Properties (C# Programming Guide)
9/3/2020 • 8 minutes to read • Edit Online
Properties combine aspects of both fields and methods. To the user of an object, a property appears to be a field,
accessing the property requires the same syntax. To the implementer of a class, a property is one or two code
blocks, representing a get accessor and/or a set accessor. The code block for the get accessor is executed when
the property is read; the code block for the set accessor is executed when the property is assigned a new value. A
property without a set accessor is considered read-only. A property without a get accessor is considered write-
only. A property that has both accessors is read-write.
Unlike fields, properties are not classified as variables. Therefore, you cannot pass a property as a ref or out
parameter.
Properties have many uses: they can validate data before allowing a change; they can transparently expose data
on a class where that data is actually retrieved from some other source, such as a database; they can take an action
when data is changed, such as raising an event, or changing the value of other fields.
Properties are declared in the class block by specifying the access level of the field, followed by the type of the
property, followed by the name of the property, and followed by a code block that declares a get -accessor and/or
a set accessor. For example:
In this example, Month is declared as a property so that the set accessor can make sure that the Month value is
set between 1 and 12. The Month property uses a private field to track the actual value. The real location of a
property's data is often referred to as the property's "backing store." It is common for properties to use private
fields as a backing store. The field is marked private in order to make sure that it can only be changed by calling
the property. For more information about public and private access restrictions, see Access Modifiers.
Auto-implemented properties provide simplified syntax for simple property declarations. For more information,
see Auto-Implemented Properties.
class Person
{
private string _name; // the name field
public string Name => _name; // the Name property
}
When you reference the property, except as the target of an assignment, the get accessor is invoked to read the
value of the property. For example:
The get accessor must end in a return or throw statement, and control cannot flow off the accessor body.
It is a bad programming style to change the state of the object by using the get accessor. For example, the
following accessor produces the side effect of changing the state of the object every time that the _number field is
accessed.
The get accessor can be used to return the field value or to compute it and return it. For example:
class Employee
{
private string _name;
public string Name => _name != null ? _name : "NA";
}
In the previous code segment, if you do not assign a value to the Name property, it will return the value NA .
class Person
{
private string _name; // the name field
public string Name // the Name property
{
get => _name;
set => _name = value;
}
}
When you assign a value to the property, the set accessor is invoked by using an argument that provides the
new value. For example:
Person person = new Person();
person.Name = "Joe"; // the set accessor is invoked here
It is an error to use the implicit parameter name, value , for a local variable declaration in a set accessor.
Remarks
Properties can be marked as public , private , protected , internal , protected internal or private protected .
These access modifiers define how users of the class can access the property. The get and set accessors for the
same property may have different access modifiers. For example, the get may be public to allow read-only
access from outside the type, and the set may be private or protected . For more information, see Access
Modifiers.
A property may be declared as a static property by using the static keyword. This makes the property available
to callers at any time, even if no instance of the class exists. For more information, see Static Classes and Static
Class Members.
A property may be marked as a virtual property by using the virtual keyword. This enables derived classes to
override the property behavior by using the override keyword. For more information about these options, see
Inheritance.
A property overriding a virtual property can also be sealed, specifying that for derived classes it is no longer
virtual. Lastly, a property can be declared abstract. This means that there is no implementation in the class, and
derived classes must write their own implementation. For more information about these options, see Abstract and
Sealed Classes and Class Members.
NOTE
It is an error to use a virtual, abstract, or override modifier on an accessor of a static property.
Example
This example demonstrates instance, static, and read-only properties. It accepts the name of the employee from
the keyboard, increments NumberOfEmployees by 1, and displays the Employee name and number.
public class Employee
{
public static int NumberOfEmployees;
private static int _counter;
private string _name;
// A Constructor:
public Employee() => _counter = ++NumberOfEmployees; // Calculate the employee's number:
}
class TestEmployee
{
static void Main()
{
Employee.NumberOfEmployees = 107;
Employee e1 = new Employee();
e1.Name = "Claude Vige";
Example
This example demonstrates how to access a property in a base class that is hidden by another property that has
the same name in a derived class:
public class Employee
{
private string _name;
public string Name
{
get => _name;
set => _name = value;
}
}
class TestHiding
{
static void Main()
{
Manager m1 = new Manager();
The cast (Employee) is used to access the hidden property in the base class:
((Employee)m1).Name = "Mary";
For more information about hiding members, see the new Modifier.
Example
In this example, two classes, Cube and Square , implement an abstract class, Shape , and override its abstract
Area property. Note the use of the override modifier on the properties. The program accepts the side as an input
and calculates the areas for the square and cube. It also accepts the area as an input and calculates the
corresponding side for the square and cube.
//constructor
public Square(double s) => side = s;
//constructor
public Cube(double s) => side = s;
class TestShapes
{
static void Main()
{
// Input the side:
System.Console.Write("Enter the side: ");
double side = double.Parse(System.Console.ReadLine());
See also
C# Programming Guide
Properties
Interface Properties
Auto-Implemented Properties
Interface Properties (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
Properties can be declared on an interface. The following example declares an interface property accessor:
Interface properties typically don't have a body. The accessors indicate whether the property is read-write, read-
only, or write-only. Unlike in classes and structs, declaring the accessors without a body doesn't declare an auto-
implemented property. Beginning with C# 8.0, an interface may define a default implementation for members,
including properties. Defining a default implementation for a property in an interface is rare because interfaces
may not define instance data fields.
Example
In this example, the interface IEmployee has a read-write property, Name , and a read-only property, Counter . The
class Employee implements the IEmployee interface and uses these two properties. The program reads the name
of a new employee and the current number of employees and displays the employee name and the computed
employee number.
You could use the fully qualified name of the property, which references the interface in which the member is
declared. For example:
string IEmployee.Name
{
get { return "Employee Name"; }
set { }
}
The preceding example demonstrates Explicit Interface Implementation. For example, if the class Employee is
implementing two interfaces ICitizen and IEmployee and both interfaces have the Name property, the explicit
interface member implementation will be necessary. That is, the following property declaration:
string IEmployee.Name
{
get { return "Employee Name"; }
set { }
}
implements the Name property on the IEmployee interface, while the following declaration:
string ICitizen.Name
{
get { return "Citizen Name"; }
set { }
}
interface IEmployee
{
string Name
{
get;
set;
}
int Counter
{
get;
}
}
// constructor
public Employee() => _counter = ++numberOfEmployees;
}
Sample output
Enter number of employees: 210
Enter the name of the new employee: Hazem Abolrous
The employee information:
Employee number: 211
Employee name: Hazem Abolrous
See also
C# Programming Guide
Properties
Using Properties
Comparison Between Properties and Indexers
Indexers
Interfaces
Restricting Accessor Accessibility (C# Programming
Guide)
9/3/2020 • 4 minutes to read • Edit Online
The get and set portions of a property or indexer are called accessors. By default these accessors have the same
visibility or access level of the property or indexer to which they belong. For more information, see accessibility
levels. However, it is sometimes useful to restrict access to one of these accessors. Typically, this involves restricting
the accessibility of the set accessor, while keeping the get accessor publicly accessible. For example:
In this example, a property called Name defines a get and set accessor. The get accessor receives the
accessibility level of the property itself, public in this case, while the set accessor is explicitly restricted by
applying the protected access modifier to the accessor itself.
Implementing Interfaces
When you use an accessor to implement an interface, the accessor may not have an access modifier. However, if
you implement the interface using one accessor, such as get , the other accessor can have an access modifier, as in
the following example:
public string Id
{
get { return _id; }
set { }
}
}
class MainClass
{
static void Main()
{
BaseClass b1 = new BaseClass();
DerivedClass d1 = new DerivedClass();
b1.Name = "Mary";
d1.Name = "John";
b1.Id = "Mary123";
d1.Id = "John123"; // The BaseClass.Id property is called.
Comments
Notice that if you replace the declaration new private string Id by new public string Id , you get the output:
Name and ID in the base class: Name-BaseClass, ID-BaseClass
See also
C# Programming Guide
Properties
Indexers
Access Modifiers
How to declare and use read write properties (C#
Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
Properties provide the convenience of public data members without the risks that come with unprotected,
uncontrolled, and unverified access to an object's data. This is accomplished through accessors: special methods
that assign and retrieve values from the underlying data member. The set accessor enables data members to be
assigned, and the get accessor retrieves data member values.
This sample shows a Person class that has two properties: Name (string) and Age (int). Both properties provide
get and set accessors, so they are considered read/write properties.
Example
class Person
{
private string _name = "N/A";
private int _age = 0;
set
{
_age = value;
}
}
class TestPerson
{
static void Main()
{
// Create a new Person object:
Person person = new Person();
// Print out the name and the age associated with the person:
Console.WriteLine("Person details - {0}", person);
Robust Programming
In the previous example, the Name and Age properties are public and include both a get and a set accessor.
This allows any object to read and write these properties. It is sometimes desirable, however, to exclude one of the
accessors. Omitting the set accessor, for example, makes the property read-only:
Alternatively, you can expose one accessor publicly but make the other private or protected. For more information,
see Asymmetric Accessor Accessibility.
Once the properties are declared, they can be used as if they were fields of the class. This allows for a very natural
syntax when both getting and setting the value of a property, as in the following statements:
person.Name = "Joe";
person.Age = 99;
Note that in a property set method a special value variable is available. This variable contains the value that the
user specified, for example:
_name = value;
Notice the clean syntax for incrementing the Age property on a Person object:
person.Age += 1;
If separate set and get methods were used to model properties, the equivalent code might look like this:
person.SetAge(person.GetAge() + 1);
Notice that ToString is not explicitly used in the program. It is invoked by default by the WriteLine calls.
See also
C# Programming Guide
Properties
Classes and Structs
Auto-Implemented Properties (C# Programming
Guide)
9/3/2020 • 2 minutes to read • Edit Online
In C# 3.0 and later, auto-implemented properties make property-declaration more concise when no additional
logic is required in the property accessors. They also enable client code to create objects. When you declare a
property as shown in the following example, the compiler creates a private, anonymous backing field that can
only be accessed through the property's get and set accessors.
Example
The following example shows a simple class that has some auto-implemented properties:
// Constructor
public Customer(double purchases, string name, int id)
{
TotalPurchases = purchases;
Name = name;
CustomerId = id;
}
// Methods
public string GetContactInfo() { return "ContactInfo"; }
public string GetTransactionHistory() { return "History"; }
class Program
{
static void Main()
{
// Intialize a new object.
Customer cust1 = new Customer(4987.63, "Northwind", 90108);
// Modify a property.
cust1.TotalPurchases += 499.99;
}
}
You can't declare auto-implemented properties in interfaces. Auto-implemented properties declare a private
instance backing field, and interfaces may not declare instance fields. Declaring a property in an interface
without defining a body declares a property with accessors that must be implemented by each type that
implements that interface.
In C# 6 and later, you can initialize auto-implemented properties similarly to fields:
public string FirstName { get; set; } = "Jane";
The class that is shown in the previous example is mutable. Client code can change the values in objects after
creation. In complex classes that contain significant behavior (methods) as well as data, it's often necessary to
have public properties. However, for small classes or structs that just encapsulate a set of values (data) and have
little or no behaviors, you should either make the objects immutable by declaring the set accessor as private
(immutable to consumers) or by declaring only a get accessor (immutable everywhere except the constructor).
For more information, see How to implement a lightweight class with auto-implemented properties.
See also
Properties
Modifiers
How to implement a lightweight class with auto-
implemented properties (C# Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
This example shows how to create an immutable lightweight class that serves only to encapsulate a set of auto-
implemented properties. Use this kind of construct instead of a struct when you must use reference type
semantics.
You can make an immutable property in two ways:
You can declare the set accessor to be private. The property is only settable within the type, but it is
immutable to consumers.
When you declare a private set accessor, you cannot use an object initializer to initialize the property. You
must use a constructor or a factory method.
You can declare only the get accessor, which makes the property immutable everywhere except in the type's
constructor.
The following example shows how a property with only get accessor differs than one with get and private set.
class Contact
{
public string Name { get; }
public string Address { get; private set; }
Example
The following example shows two ways to implement an immutable class that has auto-implemented properties.
Each way declares one of the properties with a private set and one of the properties with a get only. The first
class uses a constructor only to initialize the properties, and the second class uses a static factory method that calls
a constructor.
// Public constructor.
public Contact(string contactName, string contactAddress)
{
Name = contactName;
Address = contactAddress;
}
}
// Read-only property.
public string Address { get; }
// Private constructor.
private Contact2(string contactName, string contactAddress)
{
Name = contactName;
Address = contactAddress;
}
/* Output:
Terry Adams, 123 Main St.
Fadi Fakhouri, 345 Cypress Ave.
Hanying Feng, 678 1st Ave
Cesar Garcia, 12 108th St.
Debra Garcia, 89 E. 42nd St.
*/
The compiler creates backing fields for each auto-implemented property. The fields are not accessible directly from
source code.
See also
Properties
struct
Object and Collection Initializers
Methods (C# Programming Guide)
9/3/2020 • 10 minutes to read • Edit Online
A method is a code block that contains a series of statements. A program causes the statements to be
executed by calling the method and specifying any required method arguments. In C#, every executed
instruction is performed in the context of a method. The Main method is the entry point for every C#
application and it's called by the common language runtime (CLR) when the program is started.
NOTE
This article discusses named methods. For information about anonymous functions, see Anonymous Functions.
Method signatures
Methods are declared in a class, struct, or interface by specifying the access level such as public or private ,
optional modifiers such as abstract or sealed , the return value, the name of the method, and any method
parameters. These parts together are the signature of the method.
IMPORTANT
A return type of a method is not part of the signature of the method for the purposes of method overloading.
However, it is part of the signature of the method when determining the compatibility between a delegate and the
method that it points to.
Method parameters are enclosed in parentheses and are separated by commas. Empty parentheses indicate
that the method requires no parameters. This class contains four methods:
Method access
Calling a method on an object is like accessing a field. After the object name, add a period, the name of the
method, and parentheses. Arguments are listed within the parentheses, and are separated by commas. The
methods of the Motorcycle class can therefore be called as in the following example:
class TestMotorcycle : Motorcycle
{
moto.StartEngine();
moto.AddGas(15);
moto.Drive(5, 20);
double speed = moto.GetTopSpeed();
Console.WriteLine("My top speed is {0}", speed);
}
}
int Square(int i)
{
// Store input argument in a local variable.
int input = i;
return input * input;
}
Now, if you pass an object that is based on this type to a method, a reference to the object is passed. The
following example passes an object of type SampleRefType to method ModifyObject :
The example does essentially the same thing as the previous example in that it passes an argument by value
to a method. But, because a reference type is used, the result is different. The modification that is made in
ModifyObject to the value field of the parameter, obj , also changes the value field of the argument, rt , in
the TestRefType method. The TestRefType method displays 33 as the output.
For more information about how to pass reference types by reference and by value, see Passing Reference-
Type Parameters and Reference Types.
Return values
Methods can return a value to the caller. If the return type, the type listed before the method name, is not
void , the method can return the value by using the return keyword. A statement with the return keyword
followed by a value that matches the return type will return that value to the method caller.
The value can be returned to the caller by value or, starting with C# 7.0, by reference. Values are returned to
the caller by reference if the ref keyword is used in the method signature and it follows each return
keyword. For example, the following method signature and return statement indicate that the method returns
a variable names estDistance by reference to the caller.
The return keyword also stops the execution of the method. If the return type is void , a return statement
without a value is still useful to stop the execution of the method. Without the return keyword, the method
will stop executing when it reaches the end of the code block. Methods with a non-void return type are
required to use the return keyword to return a value. For example, these two methods use the return
keyword to return integers:
class SimpleMath
{
public int AddTwoNumbers(int number1, int number2)
{
return number1 + number2;
}
To use a value returned from a method, the calling method can use the method call itself anywhere a value of
the same type would be sufficient. You can also assign the return value to a variable. For example, the
following two code examples accomplish the same goal:
Using a local variable, in this case, result , to store a value is optional. It may help the readability of the code,
or it may be necessary if you need to store the original value of the argument for the entire scope of the
method.
To use a value returned by reference from a method, you must declare a ref local variable if you intend to
modify its value. For example, if the Planet.GetEstimatedDistance method returns a Double value by
reference, you can define it as a ref local variable with code like the following:
Returning a multi-dimensional array from a method, M , that modifies the array's contents is not necessary if
the calling function passed the array into M . You may return the resulting array from M for good style or
functional flow of values, but it is not necessary because C# passes all reference types by value, and the value
of an array reference is the pointer to the array. In the method M , any changes to the array's contents are
observable by any code that has a reference to the array, as shown in the following example:
static void Main(string[] args)
{
int[,] matrix = new int[2, 2];
FillMatrix(matrix);
// matrix is now full of -1
}
Async methods
By using the async feature, you can invoke asynchronous methods without using explicit callbacks or
manually splitting your code across multiple methods or lambda expressions.
If you mark a method with the async modifier, you can use the await operator in the method. When control
reaches an await expression in the async method, control returns to the caller, and progress in the method is
suspended until the awaited task completes. When the task is complete, execution can resume in the method.
NOTE
An async method returns to the caller when either it encounters the first awaited object that's not yet complete or it
gets to the end of the async method, whichever occurs first.
An async method can have a return type of Task<TResult>, Task, or void. The void return type is used primarily
to define event handlers, where a void return type is required. An async method that returns void can't be
awaited, and the caller of a void-returning method can't catch exceptions that the method throws.
In the following example, DelayAsync is an async method that has a return type of Task<TResult>. DelayAsync
has a return statement that returns an integer. Therefore the method declaration of DelayAsync must have a
return type of Task<int> . Because the return type is Task<int> , the evaluation of the await expression in
DoSomethingAsync produces an integer as the following statement demonstrates:
int result = await delayTask .
The Main method is an example of an async method that has a return type of Task. It goes to the
DoSomethingAsync method, and because it is expressed with a single line, it can omit the async and await
keywords. Because DoSomethingAsync is an async method, the task for the call to DoSomethingAsync must be
awaited, as the following statement shows: await DoSomethingAsync(); .
using System;
using System.Threading.Tasks;
class Program
{
static Task Main() => DoSomethingAsync();
Console.WriteLine($"Result: {result}");
}
An async method can't declare any ref or out parameters, but it can call methods that have such parameters.
For more information about async methods, see Asynchronous programming with async and await and Async
return types.
public Point Move(int dx, int dy) => new Point(x + dx, y + dy);
public void Print() => Console.WriteLine(First + " " + Last);
// Works with operators, properties, and indexers too.
public static Complex operator +(Complex a, Complex b) => a.Add(b);
public string Name => First + " " + Last;
public Customer this[long id] => store.LookupCustomer(id);
If the method returns void or is an async method, then the body of the method must be a statement
expression (same as with lambdas). For properties and indexers, they must be read only, and you don't use the
get accessor keyword.
Iterators
An iterator performs a custom iteration over a collection, such as a list or an array. An iterator uses the yield
return statement to return each element one at a time. When a yield return statement is reached, the current
location in code is remembered. Execution is restarted from that location when the iterator is called the next
time.
You call an iterator from client code by using a foreach statement.
The return type of an iterator can be IEnumerable, IEnumerable<T>, IEnumerator, or IEnumerator<T>.
For more information, see Iterators.
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source
for C# syntax and usage.
See also
C# Programming Guide
Classes and Structs
Access Modifiers
Static Classes and Static Class Members
Inheritance
Abstract and Sealed Classes and Class Members
params
return
out
ref
Passing Parameters
Local functions (C# Programming Guide)
9/3/2020 • 11 minutes to read • Edit Online
Starting with C# 7.0, C# supports local functions. Local functions are private methods of a type that are nested in
another member. They can only be called from their containing member. Local functions can be declared in and
called from:
Methods, especially iterator methods and async methods
Constructors
Property accessors
Event accessors
Anonymous methods
Lambda expressions
Finalizers
Other local functions
However, local functions can't be declared inside an expression-bodied member.
NOTE
In some cases, you can use a lambda expression to implement functionality also supported by a local function. For a
comparison, see Local functions vs. lambda expressions.
Local functions make the intent of your code clear. Anyone reading your code can see that the method is not
callable except by the containing method. For team projects, they also make it impossible for another developer to
mistakenly call the method directly from elsewhere in the class or struct.
NOTE
Prior to C# 8.0, local functions cannot include the static modifier. Including the static keyword generates compiler
error CS0106, "The modifier 'static' is not valid for this item."
In addition, attributes can't be applied to the local function or to its parameters and type parameters.
The following example defines a local function named AppendPathSeparator that is private to a method named
GetText :
using System;
using System.IO;
class Example
{
static void Main()
{
string contents = GetText(@"C:\temp", "example.txt");
Console.WriteLine("Contents of the file:\n" + contents);
}
return filepath;
}
}
}
class Example
{
static void Main()
{
IEnumerable<int> ienum = OddSequence(50, 110);
Console.WriteLine("Retrieved enumerator...");
Instead, you can throw an exception when performing validation and before retrieving the iterator by returning the
iterator from a local function, as the following example shows.
using System;
using System.Collections.Generic;
class Example
{
static void Main()
{
IEnumerable<int> ienum = OddSequence(50, 110); //Line 8
Console.WriteLine("Retrieved enumerator...");
return GetOddSequenceEnumerator();
IEnumerable<int> GetOddSequenceEnumerator()
{
for (int i = start; i <= end; i++)
{
if (i % 2 == 1)
yield return i;
}
}
}
}
// The example displays the following output:
// Unhandled Exception: System.ArgumentOutOfRangeException: Specified argument was out of the range of
valid values.
// Parameter name: end must be less than or equal to 100.
// at Sequence.<GetNumericRange>d__1.MoveNext() in Program.cs:line 8
// at Example.Main() in Program.cs:line 22
Local functions can be used in a similar way to handle exceptions outside of the asynchronous operation.
Ordinarily, exceptions thrown in async method require that you examine the inner exceptions of an
AggregateException. Local functions allow your code to fail fast and allow your exception to be both thrown and
observed synchronously.
The following example uses an asynchronous method named GetMultipleAsync to pause for a specified number of
seconds and return a value that is a random multiple of that number of seconds. The maximum delay is 5 seconds;
an ArgumentOutOfRangeException results if the value is greater than 5. As the following example shows, the
exception that is thrown when a value of 6 is passed to the GetMultipleAsync method is wrapped in an
AggregateException after the GetMultipleAsync method begins execution.
using System;
using System.Threading.Tasks;
class Example
{
static void Main()
{
int result = GetMultipleAsync(6).Result; //Line 8
Console.WriteLine($"The returned value is {result:N0}");
}
As we did with the method iterator, we can refactor the code from this example to perform the validation before
calling the asynchronous method. As the output from the following example shows, the
ArgumentOutOfRangeException is not wrapped in a AggregateException.
using System;
using System.Threading.Tasks;
class Example
{
static void Main()
{
int result = GetMultiple(6).Result; // Line 8
Console.WriteLine($"The returned value is {result:N0}");
}
return GetValueAsync();
return nthFactorial(n);
}
The local functions have names. The lambda expressions are anonymous methods that are assigned to variables
that are Func or Action types. When you declare a local function, the argument types and return type are part of
the function declaration. Instead of being part of the body of the lambda expression, the argument types and return
type are part of the lambda expression's variable type declaration. Those two differences may result in clearer code.
Local functions have different rules for definite assignment than lambda expressions. A local function declaration
can be referenced from any code location where it is in scope. A lambda expression must be assigned to a delegate
variable before it can be accessed (or called through the delegate referencing the lambda expression). Notice that
the version using the lambda expression must declare and initialize the lambda expression nthFactorial before
defining it. Not doing so results in a compile time error for referencing nthFactorial before assigning it. These
differences mean that recursive algorithms are easier to create using local functions. You can declare and define a
local function that calls itself. Lambda expressions must be declared, and assigned a default value before they can
be re-assigned to a body that references the same lambda expression.
Definite assignment rules also affect any variables that are captured by the local function or lambda expression.
Both local functions and lambda expression rules demand that any captured variables are definitely assigned at the
point when the local function or lambda expression is converted to a delegate. The difference is that lambda
expressions are converted to delegates when they are declared. Local functions are converted to delegates only
when used as a delegate. If you declare a local function and only reference it by calling it like a method, it will not
be converted to a delegate. That rule enables you to declare a local function at any convenient location in its
enclosing scope. It's common to declare local functions at the end of the parent method, after any return
statements.
Third, the compiler can perform static analysis that enables local functions to definitely assign captured variables in
the enclosing scope. Consider this example:
int M()
{
int y;
LocalFunction();
return y;
The compiler can determine that LocalFunction definitely assigns y when called. Because LocalFunction is called
before the return statement, y is definitely assigned at the return statement.
The analysis that enables the example analysis enables the fourth difference. Depending on their use, local
functions can avoid heap allocations that are always necessary for lambda expressions. If a local function is never
converted to a delegate, and none of the variables captured by the local function is captured by other lambdas or
local functions that are converted to delegates, the compiler can avoid heap allocations.
Consider this async example:
public Task<string> PerformLongRunningWorkLambda(string address, int index, string name)
{
if (string.IsNullOrWhiteSpace(address))
throw new ArgumentException(message: "An address is required", paramName: nameof(address));
if (index < 0)
throw new ArgumentOutOfRangeException(paramName: nameof(index), message: "The index must be non-
negative");
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException(message: "You must supply a name", paramName: nameof(name));
return longRunningWorkImplementation();
}
The closure for this lambda expression contains the address , index and name variables. In the case of local
functions, the object that implements the closure may be a struct type. That struct type would be passed by
reference to the local function. This difference in implementation would save on an allocation.
The instantiation necessary for lambda expressions means extra memory allocations, which may be a performance
factor in time-critical code paths. Local functions do not incur this overhead. In the example above, the local
functions version has 2 fewer allocations than the lambda expression version.
NOTE
The local function equivalent of this method also uses a class for the closure. Whether the closure for a local function is
implemented as a class or a struct is an implementation detail. A local function may use a struct whereas a lambda
will always use a class .
return longRunningWorkImplementation();
One final advantage not demonstrated in this sample is that local functions can be implemented as iterators, using
the yield return syntax to produce a sequence of values. The yield return statement is not allowed in lambda
expressions.
While local functions may seem redundant to lambda expressions, they actually serve different purposes and have
different uses. Local functions are more efficient for the case when you want to write a function that is called only
from the context of another method.
See also
Methods
Ref returns and ref locals
3/12/2020 • 6 minutes to read • Edit Online
Starting with C# 7.0, C# supports reference return values (ref returns). A reference return value allows a method
to return a reference to a variable, rather than a value, back to a caller. The caller can then choose to treat the
returned variable as if it were returned by value or by reference. The caller can create a new variable that is itself a
reference to the returned value, called a ref local.
Ref locals
Assume the GetContactInformation method is declared as a ref return:
A by-value assignment reads the value of a variable and assigns it to a new variable:
The preceding assignment declares p as a local variable. Its initial value is copied from reading the value returned
by GetContactInformation . Any future assignments to p will not change the value of the variable returned by
GetContactInformation . The variable p is no longer an alias to the variable returned.
You declare a ref local variable to copy the alias to the original value. In the following assignment, p is an alias to
the variable returned from GetContactInformation .
Subsequent usage of p is the same as using the variable returned by GetContactInformation because p is an
alias for that variable. Changes to p also change the variable returned from GetContactInformation .
The ref keyword is used both before the local variable declaration and before the method call.
You can access a value by reference in the same way. In some cases, accessing a value by reference increases
performance by avoiding a potentially expensive copy operation. For example, the following statement shows how
one can define a ref local value that is used to reference a value.
The ref keyword is used both before the local variable declaration and before the value in the second example.
Failure to include both ref keywords in the variable declaration and assignment in both examples results in
compiler error CS8172, "Cannot initialize a by-reference variable with a value."
Prior to C# 7.3, ref local variables couldn't be reassigned to refer to different storage after being initialized. That
restriction has been removed. The following example shows a reassignment:
Ref local variables must still be initialized when they are declared.
using System;
class NumberStore
{
int[] numbers = { 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023 };
The following example calls the NumberStore.FindNumber method to retrieve the first value that is greater than or
equal to 16. The caller then doubles the value returned by the method. The output from the example shows the
change reflected in the value of the array elements of the NumberStore instance.
Without support for reference return values, such an operation is performed by returning the index of the array
element along with its value. The caller can then use this index to modify the value in a separate method call.
However, the caller can also modify the index to access and possibly modify other array values.
The following example shows how the FindNumber method could be rewritten after C# 7.3 to use ref local
reassignment:
using System;
class NumberStore
{
int[] numbers = { 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023 };
This second version is more efficient with longer sequences in scenarios where the number sought is closer to the
end of the array.
See also
ref keyword
Write safe efficient code
Passing Parameters (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
In C#, arguments can be passed to parameters either by value or by reference. Passing by reference enables
function members, methods, properties, indexers, operators, and constructors to change the value of the
parameters and have that change persist in the calling environment. To pass a parameter by reference with the
intent of changing the value, use the ref , or out keyword. To pass by reference with the intent of avoiding
copying but not changing the value, use the in modifier. For simplicity, only the ref keyword is used in the
examples in this topic. For more information about the difference between in , ref , and out , see in, ref, and out.
The following example illustrates the difference between value and reference parameters.
class Program
{
static void Main(string[] args)
{
int arg;
// Passing by value.
// The value of arg in Main is not changed.
arg = 4;
squareVal(arg);
Console.WriteLine(arg);
// Output: 4
// Passing by reference.
// The value of arg in Main is changed.
arg = 4;
squareRef(ref arg);
Console.WriteLine(arg);
// Output: 16
}
// Passing by reference
static void squareRef(ref int refParameter)
{
refParameter *= refParameter;
}
}
C# Language Specification
For more information, see Argument lists in the C# Language Specification. The language specification is the
definitive source for C# syntax and usage.
See also
C# Programming Guide
Methods
Passing Value-Type Parameters (C# Programming
Guide)
9/3/2020 • 3 minutes to read • Edit Online
A value-type variable contains its data directly as opposed to a reference-type variable, which contains a reference
to its data. Passing a value-type variable to a method by value means passing a copy of the variable to the method.
Any changes to the parameter that take place inside the method have no effect on the original data stored in the
argument variable. If you want the called method to change the value of the argument, you must pass it by
reference, using the ref or out keyword. You may also use the in keyword to pass a value parameter by reference to
avoid the copy while guaranteeing that the value will not be changed. For simplicity, the following examples use
ref .
class PassingValByVal
{
static void SquareIt(int x)
// The parameter x is passed by value.
// Changes to x will not affect the original value of x.
{
x *= x;
System.Console.WriteLine("The value inside the method: {0}", x);
}
static void Main()
{
int n = 5;
System.Console.WriteLine("The value before calling the method: {0}", n);
The variable n is a value type. It contains its data, the value 5 . When SquareIt is invoked, the contents of n are
copied into the parameter x , which is squared inside the method. In Main , however, the value of n is the same
after calling the SquareIt method as it was before. The change that takes place inside the method only affects the
local variable x .
class PassingValByRef
{
static void SquareIt(ref int x)
// The parameter x is passed by reference.
// Changes to x will affect the original value of x.
{
x *= x;
System.Console.WriteLine("The value inside the method: {0}", x);
}
static void Main()
{
int n = 5;
System.Console.WriteLine("The value before calling the method: {0}", n);
In this example, it is not the value of n that is passed; rather, a reference to n is passed. The parameter x is not
an int; it is a reference to an int , in this case, a reference to n . Therefore, when x is squared inside the method,
what actually is squared is what x refers to, n .
When you call the SwapByRef method, use the ref keyword in the call, as shown in the following example.
static void Main()
{
int i = 2, j = 3;
System.Console.WriteLine("i = {0} j = {1}" , i, j);
See also
C# Programming Guide
Passing Parameters
Passing Reference-Type Parameters
Passing Reference-Type Parameters (C#
Programming Guide)
9/3/2020 • 4 minutes to read • Edit Online
A variable of a reference type does not contain its data directly; it contains a reference to its data. When you pass a
reference-type parameter by value, it is possible to change the data belonging to the referenced object, such as the
value of a class member. However, you cannot change the value of the reference itself; for example, you cannot use
the same reference to allocate memory for a new object and have it persist outside the method. To do that, pass
the parameter using the ref or out keyword. For simplicity, the following examples use ref .
class PassingRefByVal
{
static void Change(int[] pArray)
{
pArray[0] = 888; // This change affects the original element.
pArray = new int[5] {-3, -1, -2, -3, -4}; // This change is local.
System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]);
}
Change(arr);
System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr [0]);
}
}
/* Output:
Inside Main, before calling the method, the first element is: 1
Inside the method, the first element is: -3
Inside Main, after calling the method, the first element is: 888
*/
In the preceding example, the array, arr , which is a reference type, is passed to the method without the ref
parameter. In such a case, a copy of the reference, which points to arr , is passed to the method. The output shows
that it is possible for the method to change the contents of an array element, in this case from 1 to 888 .
However, allocating a new portion of memory by using the new operator inside the Change method makes the
variable pArray reference a new array. Thus, any changes after that will not affect the original array, arr , which is
created inside Main . In fact, two arrays are created in this example, one inside Main and one inside the Change
method.
class PassingRefByRef
{
static void Change(ref int[] pArray)
{
// Both of the following changes will affect the original variables:
pArray[0] = 888;
pArray = new int[5] {-3, -1, -2, -3, -4};
System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]);
}
Change(ref arr);
System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr[0]);
}
}
/* Output:
Inside Main, before calling the method, the first element is: 1
Inside the method, the first element is: -3
Inside Main, after calling the method, the first element is: -3
*/
All of the changes that take place inside the method affect the original array in Main . In fact, the original array is
reallocated using the new operator. Thus, after calling the Change method, any reference to arr points to the
five-element array, which is created in the Change method.
In this example, the parameters need to be passed by reference to affect the variables in the calling program. If you
remove the ref keyword from both the method header and the method call, no changes will take place in the
calling program.
For more information about strings, see string.
See also
C# Programming Guide
Passing Parameters
ref
in
out
Reference Types
How to know the difference between passing a struct
and passing a class reference to a method (C#
Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
The following example demonstrates how passing a struct to a method differs from passing a class instance to a
method. In the example, both of the arguments (struct and class instance) are passed by value, and both methods
change the value of one field of the argument. However, the results of the two methods are not the same because
what is passed when you pass a struct differs from what is passed when you pass an instance of a class.
Because a struct is a value type, when you pass a struct by value to a method, the method receives and operates on
a copy of the struct argument. The method has no access to the original struct in the calling method and therefore
can't change it in any way. The method can change only the copy.
A class instance is a reference type, not a value type. When a reference type is passed by value to a method, the
method receives a copy of the reference to the class instance. That is, the called method receives a copy of the
address of the instance, and the calling method retains the original address of the instance. The class instance in the
calling method has an address, the parameter in the called method has a copy of the address, and both addresses
refer to the same object. Because the parameter contains only a copy of the address, the called method cannot
change the address of the class instance in the calling method. However, the called method can use the copy of the
address to access the class members that both the original address and the copy of the address reference. If the
called method changes a class member, the original class instance in the calling method also changes.
The output of the following example illustrates the difference. The value of the willIChange field of the class
instance is changed by the call to method ClassTaker because the method uses the address in the parameter to
find the specified field of the class instance. The willIChange field of the struct in the calling method is not changed
by the call to method StructTaker because the value of the argument is a copy of the struct itself, not a copy of its
address. StructTaker changes the copy, and the copy is lost when the call to StructTaker is completed.
Example
class TheClass
{
public string willIChange;
}
struct TheStruct
{
public string willIChange;
}
class TestClassAndStruct
{
static void ClassTaker(TheClass c)
{
c.willIChange = "Changed";
}
ClassTaker(testClass);
StructTaker(testStruct);
See also
C# Programming Guide
Classes
Structure types
Passing Parameters
Implicitly typed local variables (C# Programming
Guide)
9/3/2020 • 5 minutes to read • Edit Online
Local variables can be declared without giving an explicit type. The var keyword instructs the compiler to infer
the type of the variable from the expression on the right side of the initialization statement. The inferred type
may be a built-in type, an anonymous type, a user-defined type, or a type defined in the .NET class library. For
more information about how to initialize arrays with var , see Implicitly Typed Arrays.
The following examples show various ways in which local variables can be declared with var :
// i is compiled as an int
var i = 5;
// s is compiled as a string
var s = "Hello";
// a is compiled as int[]
var a = new[] { 0, 1, 2 };
It is important to understand that the var keyword does not mean "variant" and does not indicate that the
variable is loosely typed, or late-bound. It just means that the compiler determines and assigns the most
appropriate type.
The var keyword may be used in the following contexts:
On local variables (variables declared at method scope) as shown in the previous example.
In a for initialization statement.
In a using statement.
class ImplicitlyTypedLocals2
{
static void Main()
{
string[] words = { "aPPLE", "BlUeBeRrY", "cHeRry" };
Remarks
The following restrictions apply to implicitly-typed variable declarations:
var can only be used when a local variable is declared and initialized in the same statement; the
variable cannot be initialized to null, or to a method group or an anonymous function.
var cannot be used on fields at class scope.
Variables declared by using var cannot be used in the initialization expression. In other words, this
expression is legal: int i = (i = 20); but this expression produces a compile-time error:
var i = (i = 20);
bookTitles is a class field given the type var . As the field has no expression to evaluate, it is impossible for
the compiler to infer what type bookTitles is supposed to be. In addition, adding an expression to the field
(like you would for a local variable) is also insufficient:
When the compiler encounters fields during code compilation, it records each field's type before processing
any expressions associated with it. The compiler encounters the same paradox trying to parse bookTitles : it
needs to know the type of the field, but the compiler would normally determine var 's type by analyzing the
expression, which isn't possible without knowing the type beforehand.
You may find that var can also be useful with query expressions in which the exact constructed type of the
query variable is difficult to determine. This can occur with grouping and ordering operations.
The var keyword can also be useful when the specific type of the variable is tedious to type on the keyboard,
or is obvious, or does not add to the readability of the code. One example where var is helpful in this manner
is with nested generic types such as those used with group operations. In the following query, the type of the
query variable is IEnumerable<IGrouping<string, Student>> . As long as you and others who must maintain your
code understand this, there is no problem with using implicit typing for convenience and brevity.
// Same as previous example except we use the entire last name as a key.
// Query variable is an IEnumerable<IGrouping<string, Student>>
var studentQuery3 =
from student in students
group student by student.Last;
The use of var helps simplify your code, but its use should be restricted to cases where it is required, or when
it makes your code easier to read. For more information about when to use var properly, see the Implicitly
typed local variables section on the C# Coding Guidelines article.
See also
C# Reference
Implicitly Typed Arrays
How to use implicitly typed local variables and arrays in a query expression
Anonymous Types
Object and Collection Initializers
var
LINQ in C#
LINQ (Language-Integrated Query)
for
foreach, in
using Statement
How to use implicitly typed local variables and arrays
in a query expression (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
You can use implicitly typed local variables whenever you want the compiler to determine the type of a local
variable. You must use implicitly typed local variables to store anonymous types, which are often used in query
expressions. The following examples illustrate both optional and required uses of implicitly typed local variables in
queries.
Implicitly typed local variables are declared by using the var contextual keyword. For more information, see
Implicitly Typed Local Variables and Implicitly Typed Arrays.
Example
The following example shows a common scenario in which the var keyword is required: a query expression that
produces a sequence of anonymous types. In this scenario, both the query variable and the iteration variable in the
foreach statement must be implicitly typed by using var because you do not have access to a type name for the
anonymous type. For more information about anonymous types, see Anonymous Types.
Example
The following example uses the var keyword in a situation that is similar, but in which the use of var is optional.
Because student.LastName is a string, execution of the query returns a sequence of strings. Therefore, the type of
queryID could be declared as System.Collections.Generic.IEnumerable<string> instead of var . Keyword var is
used for convenience. In the example, the iteration variable in the foreach statement is explicitly typed as a string,
but it could instead be declared by using var . Because the type of the iteration variable is not an anonymous type,
the use of var is an option, not a requirement. Remember, var itself is not a type, but an instruction to the
compiler to infer and assign the type.
// Variable queryId could be declared by using
// System.Collections.Generic.IEnumerable<string>
// instead of var.
var queryId =
from student in students
where student.Id > 111
select student.LastName;
See also
C# Programming Guide
Extension Methods
LINQ (Language-Integrated Query)
var
LINQ in C#
Extension Methods (C# Programming Guide)
9/3/2020 • 9 minutes to read • Edit Online
Extension methods enable you to "add" methods to existing types without creating a new derived type,
recompiling, or otherwise modifying the original type. Extension methods are static methods, but they're
called as if they were instance methods on the extended type. For client code written in C#, F# and Visual Basic,
there's no apparent difference between calling an extension method and the methods defined in a type.
The most common extension methods are the LINQ standard query operators that add query functionality to
the existing System.Collections.IEnumerable and System.Collections.Generic.IEnumerable<T> types. To use the
standard query operators, first bring them into scope with a using System.Linq directive. Then any type that
implements IEnumerable<T> appears to have instance methods such as GroupBy, OrderBy, Average, and so
on. You can see these additional methods in IntelliSense statement completion when you type "dot" after an
instance of an IEnumerable<T> type such as List<T> or Array.
OrderBy Example
The following example shows how to call the standard query operator OrderBy method on an array of
integers. The expression in parentheses is a lambda expression. Many standard query operators take lambda
expressions as parameters, but this isn't a requirement for extension methods. For more information, see
Lambda Expressions.
class ExtensionMethods2
{
Extension methods are defined as static methods but are called by using instance method syntax. Their first
parameter specifies which type the method operates on. The parameter is preceded by the this modifier.
Extension methods are only in scope when you explicitly import the namespace into your source code with a
using directive.
The following example shows an extension method defined for the System.String class. It's defined inside a
non-nested, non-generic static class:
namespace ExtensionMethods
{
public static class MyExtensions
{
public static int WordCount(this String str)
{
return str.Split(new char[] { ' ', '.', '?' },
StringSplitOptions.RemoveEmptyEntries).Length;
}
}
}
The WordCount extension method can be brought into scope with this using directive:
using ExtensionMethods;
You invoke the extension method in your code with instance method syntax. The intermediate language (IL)
generated by the compiler translates your code into a call on the static method. The principle of encapsulation
is not really being violated. Extension methods cannot access private variables in the type they are extending.
For more information, see How to implement and call a custom extension method.
In general, you'll probably be calling extension methods far more often than implementing your own. Because
extension methods are called by using instance method syntax, no special knowledge is required to use them
from client code. To enable extension methods for a particular type, just add a using directive for the
namespace in which the methods are defined. For example, to use the standard query operators, add this
using directive to your code:
using System.Linq;
(You may also have to add a reference to System.Core.dll.) You'll notice that the standard query operators now
appear in IntelliSense as additional methods available for most IEnumerable<T> types.
Example
The following example demonstrates the rules that the C# compiler follows in determining whether to bind a
method call to an instance method on the type, or to an extension method. The static class Extensions
contains extension methods defined for any type that implements IMyInterface . Classes A , B , and C all
implement the interface.
The MethodB extension method is never called because its name and signature exactly match methods already
implemented by the classes.
When the compiler can't find an instance method with a matching signature, it will bind to a matching
extension method if one exists.
// Define three classes that implement IMyInterface, and then use them to test
// the extension methods.
namespace ExtensionMethodsDemo1
{
using System;
using Extensions;
using DefineIMyInterface;
class A : IMyInterface
{
public void MethodB() { Console.WriteLine("A.MethodB()"); }
}
}
class B : IMyInterface
{
public void MethodB() { Console.WriteLine("B.MethodB()"); }
public void MethodA(int i) { Console.WriteLine("B.MethodA(int i)"); }
}
class C : IMyInterface
{
public void MethodB() { Console.WriteLine("C.MethodB()"); }
public void MethodA(object obj)
{
Console.WriteLine("C.MethodA(object obj)");
}
}
class ExtMethodDemo
{
static void Main(string[] args)
{
// Declare an instance of class A, class B, and class C.
A a = new A();
B b = new B();
C c = new C();
General Guidelines
While it's still considered preferable to add functionality by modifying an object's code or deriving a new type
whenever it's reasonable and possible to do so, extension methods have become a crucial option for creating
reusable functionality throughout the .NET ecosystem. For those occasions when the original source isn't
under your control, when a derived object is inappropriate or impossible, or when the functionality shouldn't
be exposed beyond its applicable scope, Extension methods are an excellent choice.
For more information on derived types, see Inheritance.
When using an extension method to extend a type whose source code you aren't in control of, you run the risk
that a change in the implementation of the type will cause your extension method to break.
If you do implement extension methods for a given type, remember the following points:
An extension method will never be called if it has the same signature as a method defined in the type.
Extension methods are brought into scope at the namespace level. For example, if you have multiple static
classes that contain extension methods in a single namespace named Extensions , they'll all be brought
into scope by the using Extensions; directive.
For a class library that you implemented, you shouldn't use extension methods to avoid incrementing the
version number of an assembly. If you want to add significant functionality to a library for which you own the
source code, follow the .NET guidelines for assembly versioning. For more information, see Assembly
Versioning.
See also
C# Programming Guide
Parallel Programming Samples (these include many example extension methods)
Lambda Expressions
Standard Query Operators Overview
Conversion rules for Instance parameters and their impact
Extension methods Interoperability between languages
Extension methods and Curried Delegates
Extension method Binding and Error reporting
How to implement and call a custom extension
method (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
This topic shows how to implement your own extension methods for any .NET type. Client code can use your
extension methods by adding a reference to the DLL that contains them, and adding a using directive that specifies
the namespace in which the extension methods are defined.
Example
The following example implements an extension method named WordCount in the
CustomExtensions.StringExtension class. The method operates on the String class, which is specified as the first
method parameter. The CustomExtensions namespace is imported into the application namespace, and the method
is called inside the Main method.
using System.Linq;
using System.Text;
using System;
namespace CustomExtensions
{
// Extension methods must be defined in a static class.
public static class StringExtension
{
// This is the extension method.
// The first parameter takes the "this" modifier
// and specifies the type for which the method is defined.
public static int WordCount(this String str)
{
return str.Split(new char[] {' ', '.','?'}, StringSplitOptions.RemoveEmptyEntries).Length;
}
}
}
namespace Extension_Methods_Simple
{
// Import the extension method namespace.
using CustomExtensions;
class Program
{
static void Main(string[] args)
{
string s = "The quick brown fox jumped over the lazy dog.";
// Call the method as if it were an
// instance method on the type. Note that the first
// parameter is not specified by the calling code.
int i = s.WordCount();
System.Console.WriteLine("Word count of s is {0}", i);
}
}
}
.NET Security
Extension methods present no specific security vulnerabilities. They can never be used to impersonate existing
methods on a type, because all name collisions are resolved in favor of the instance or static method defined by
the type itself. Extension methods cannot access any private data in the extended class.
See also
C# Programming Guide
Extension Methods
LINQ (Language-Integrated Query)
Static Classes and Static Class Members
protected
internal
public
this
namespace
How to create a new method for an enumeration (C#
Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
You can use extension methods to add functionality specific to a particular enum type.
Example
In the following example, the Grades enumeration represents the possible letter grades that a student may receive
in a class. An extension method named Passing is added to the Grades type so that each instance of that type
now "knows" whether it represents a passing grade or not.
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
namespace EnumExtension
{
// Define an extension method in a non-nested static class.
public static class Extensions
{
public static Grades minPassing = Grades.D;
public static bool Passing(this Grades grade)
{
return grade >= minPassing;
}
}
Extensions.minPassing = Grades.C;
Console.WriteLine("\r\nRaising the bar!\r\n");
Console.WriteLine("First {0} a passing grade.", g1.Passing() ? "is" : "is not");
Console.WriteLine("Second {0} a passing grade.", g2.Passing() ? "is" : "is not");
}
}
}
/* Output:
First is a passing grade.
Second is not a passing grade.
Note that the Extensions class also contains a static variable that is updated dynamically and that the return value
of the extension method reflects the current value of that variable. This demonstrates that, behind the scenes,
extension methods are invoked directly on the static class in which they are defined.
See also
C# Programming Guide
Extension Methods
Named and Optional Arguments (C# Programming
Guide)
9/3/2020 • 8 minutes to read • Edit Online
C# 4 introduces named and optional arguments. Named arguments enable you to specify an argument for a
particular parameter by associating the argument with the parameter's name rather than with the parameter's
position in the parameter list. Optional arguments enable you to omit arguments for some parameters. Both
techniques can be used with methods, indexers, constructors, and delegates.
When you use named and optional arguments, the arguments are evaluated in the order in which they appear in
the argument list, not the parameter list.
Named and optional parameters, when used together, enable you to supply arguments for only a few parameters
from a list of optional parameters. This capability greatly facilitates calls to COM interfaces such as the Microsoft
Office Automation APIs.
Named Arguments
Named arguments free you from the need to remember or to look up the order of parameters in the parameter
lists of called methods. The parameter for each argument can be specified by parameter name. For example, a
function that prints order details (such as, seller name, order number & product name) can be called in the
standard way by sending arguments by position, in the order defined by the function.
PrintOrderDetails("Gift Shop", 31, "Red Mug");
If you do not remember the order of the parameters but know their names, you can send the arguments in any
order.
PrintOrderDetails(orderNum: 31, productName: "Red Mug", sellerName: "Gift Shop");
Named arguments also improve the readability of your code by identifying what each argument represents. In
the example method below, the sellerName cannot be null or white space. As both sellerName and productName
are string types, instead of sending arguments by position, it makes sense to use named arguments to
disambiguate the two and reduce confusion for anyone reading the code.
Named arguments, when used with positional arguments, are valid as long as
they're not followed by any positional arguments, or
PrintOrderDetails("Gift Shop", 31, productName: "Red Mug");
starting with C# 7.2, they're used in the correct position. In the example below, the parameter orderNum is in
the correct position but isn't explicitly named.
PrintOrderDetails(sellerName: "Gift Shop", 31, productName: "Red Mug");
Positional arguments that follow any out-of-order named arguments are invalid.
// This generates CS1738: Named argument specifications must appear after all fixed arguments have been
specified.
PrintOrderDetails(productName: "Red Mug", 31, "Gift Shop");
Example
The following code implements the examples from this section along with some additional ones.
class NamedExample
{
static void Main(string[] args)
{
// The method can be called in the normal way, by using positional arguments.
PrintOrderDetails("Gift Shop", 31, "Red Mug");
Optional Arguments
The definition of a method, constructor, indexer, or delegate can specify that its parameters are required or that
they are optional. Any call must provide arguments for all required parameters, but can omit arguments for
optional parameters.
Each optional parameter has a default value as part of its definition. If no argument is sent for that parameter, the
default value is used. A default value must be one of the following types of expressions:
a constant expression;
an expression of the form new ValType() , where ValType is a value type, such as an enum or a struct;
an expression of the form default(ValType), where ValType is a value type.
Optional parameters are defined at the end of the parameter list, after any required parameters. If the caller
provides an argument for any one of a succession of optional parameters, it must provide arguments for all
preceding optional parameters. Comma-separated gaps in the argument list are not supported. For example, in
the following code, instance method ExampleMethod is defined with one required and two optional parameters.
public void ExampleMethod(int required, string optionalstr = "default string",
int optionalint = 10)
The following call to ExampleMethod causes a compiler error, because an argument is provided for the third
parameter but not for the second.
//anExample.ExampleMethod(3, ,4);
However, if you know the name of the third parameter, you can use a named argument to accomplish the task.
anExample.ExampleMethod(3, optionalint: 4);
IntelliSense uses brackets to indicate optional parameters, as shown in the following illustration:
NOTE
You can also declare optional parameters by using the .NET OptionalAttribute class. OptionalAttribute parameters do
not require a default value.
Example
In the following example, the constructor for ExampleClass has one parameter, which is optional. Instance method
ExampleMethod has one required parameter, required , and two optional parameters, optionalstr and
optionalint . The code in Main shows the different ways in which the constructor and method can be invoked.
namespace OptionalNamespace
{
class OptionalExample
{
static void Main(string[] args)
{
// Instance anExample does not send an argument for the constructor's
// optional parameter.
ExampleClass anExample = new ExampleClass();
anExample.ExampleMethod(1, "One", 1);
anExample.ExampleMethod(2, "Two");
anExample.ExampleMethod(3);
class ExampleClass
{
private string _name;
COM Interfaces
Named and optional arguments, along with support for dynamic objects and other enhancements, greatly
improve interoperability with COM APIs, such as Office Automation APIs.
For example, the AutoFormat method in the Microsoft Office Excel Range interface has seven parameters, all of
which are optional. These parameters are shown in the following illustration:
In C# 3.0 and earlier versions, an argument is required for each parameter, as shown in the following example.
// In C# 3.0 and earlier versions, you need to supply an argument for
// every parameter. The following call specifies a value for the first
// parameter, and sends a placeholder value for the other six. The
// default values are used for those parameters.
var excelApp = new Microsoft.Office.Interop.Excel.Application();
excelApp.Workbooks.Add();
excelApp.Visible = true;
var myFormat =
Microsoft.Office.Interop.Excel.XlRangeAutoFormat.xlRangeAutoFormatAccounting1;
However, you can greatly simplify the call to AutoFormat by using named and optional arguments, introduced in
C# 4.0. Named and optional arguments enable you to omit the argument for an optional parameter if you do not
want to change the parameter's default value. In the following call, a value is specified for only one of the seven
parameters.
// The following code shows the same call to AutoFormat in C# 4.0. Only
// the argument for which you want to provide a specific value is listed.
excelApp.Range["A1", "B4"].AutoFormat( Format: myFormat );
For more information and examples, see How to use named and optional arguments in Office programming and
How to access Office interop objects by using C# features.
Overload Resolution
Use of named and optional arguments affects overload resolution in the following ways:
A method, indexer, or constructor is a candidate for execution if each of its parameters either is optional or
corresponds, by name or by position, to a single argument in the calling statement, and that argument can
be converted to the type of the parameter.
If more than one candidate is found, overload resolution rules for preferred conversions are applied to the
arguments that are explicitly specified. Omitted arguments for optional parameters are ignored.
If two candidates are judged to be equally good, preference goes to a candidate that does not have
optional parameters for which arguments were omitted in the call. This is a consequence of a general
preference in overload resolution for candidates that have fewer parameters.
C# Language Specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
How to use named and optional arguments in Office programming
Using Type dynamic
Using Constructors
Using Indexers
How to use named and optional arguments in Office
programming (C# Programming Guide)
9/3/2020 • 5 minutes to read • Edit Online
Named arguments and optional arguments, introduced in C# 4, enhance convenience, flexibility, and readability in
C# programming. In addition, these features greatly facilitate access to COM interfaces such as the Microsoft
Office automation APIs.
In the following example, method ConvertToTable has sixteen parameters that represent characteristics of a table,
such as number of columns and rows, formatting, borders, fonts, and colors. All sixteen parameters are optional,
because most of the time you do not want to specify particular values for all of them. However, without named and
optional arguments, a value or a placeholder value has to be provided for each parameter. With named and
optional arguments, you specify values only for the parameters that are required for your project.
You must have Microsoft Office Word installed on your computer to complete these procedures.
NOTE
Your computer might show different names or locations for some of the Visual Studio user interface elements in the
following instructions. The Visual Studio edition that you have and the settings that you use determine these elements. For
more information, see Personalizing the IDE.
To add a reference
1. In Solution Explorer , right-click your project's name and then click Add Reference . The Add Reference
dialog box appears.
2. On the .NET page, select Microsoft.Office.Interop.Word in the Component Name list.
3. Click OK .
2. Add the following code at the end of the method to define where to display text in the document, and what
text to display:
DisplayInWord();
2. Press CTRL+F5 to run the project. A Word document appears that contains the specified text.
// Convert to a simple table. The table will have a single row with
// three columns.
range.ConvertToTable(Separator: ",");
In earlier versions of C#, the call to ConvertToTable requires a reference argument for each parameter, as
shown in the following code:
2. To specify a predefined format for the table, replace the last line in DisplayInWord with the following
statement and then type CTRL+F5. The format can be any of the WdTableFormat constants.
Example
The following code includes the full example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Word = Microsoft.Office.Interop.Word;
namespace OfficeHowTo
{
class WordProgram
{
static void Main(string[] args)
{
DisplayInWord();
}
// Next, use the ConvertToTable method to put the text into a table.
// The method has 16 optional parameters. You only have to specify
// values for those you want to change.
// Convert to a simple table. The table will have a single row with
// three columns.
range.ConvertToTable(Separator: ",");
See also
Named and Optional Arguments
Constructors (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
Whenever a class or struct is created, its constructor is called. A class or struct may have multiple constructors
that take different arguments. Constructors enable the programmer to set default values, limit instantiation,
and write code that is flexible and easy to read. For more information and examples, see Using Constructors
and Instance Constructors.
Parameterless constructors
If you don't provide a constructor for your class, C# creates one by default that instantiates the object and sets
member variables to the default values as listed in the Default values of C# types article. If you don't provide a
constructor for your struct, C# relies on an implicit parameterless constructor to automatically initialize each
field to its default value. For more information and examples, see Instance constructors.
Constructor syntax
A constructor is a method whose name is the same as the name of its type. Its method signature includes only
the method name and its parameter list; it does not include a return type. The following example shows the
constructor for a class named Person .
If a constructor can be implemented as a single statement, you can use an expression body definition. The
following example defines a Location class whose constructor has a single string parameter named name. The
expression body definition assigns the argument to the locationName field.
static Adult()
{
minimumAge = 18;
}
You can also define a static constructor with an expression body definition, as the following example shows.
In This Section
Using Constructors
Instance Constructors
Private Constructors
Static Constructors
How to write a copy constructor
See also
C# Programming Guide
Classes and Structs
Finalizers
static
Why Do Initializers Run In The Opposite Order As Constructors? Part One
Using Constructors (C# Programming Guide)
9/3/2020 • 4 minutes to read • Edit Online
When a class or struct is created, its constructor is called. Constructors have the same name as the class or struct,
and they usually initialize the data members of the new object.
In the following example, a class named Taxi is defined by using a simple constructor. This class is then
instantiated with the new operator. The Taxi constructor is invoked by the new operator immediately after
memory is allocated for the new object.
class TestTaxi
{
static void Main()
{
Taxi t = new Taxi();
Console.WriteLine(t.IsInitialized);
}
}
A constructor that takes no parameters is called a parameterless constructor. Parameterless constructors are
invoked whenever an object is instantiated by using the new operator and no arguments are provided to new .
For more information, see Instance Constructors.
Unless the class is static, classes without constructors are given a public parameterless constructor by the C#
compiler in order to enable class instantiation. For more information, see Static Classes and Static Class Members.
You can prevent a class from being instantiated by making the constructor private, as follows:
class NLog
{
// Private Constructor:
private NLog() { }
The following code, however, causes a compiler error because it does not use new , and because it tries to use an
object that has not been initialized:
int i;
Console.WriteLine(i);
Alternatively, objects based on structs (including all built-in numeric types) can be initialized or assigned and
then used as in the following example:
A constructor can use the base keyword to call the constructor of a base class. For example:
In this example, the constructor for the base class is called before the block for the constructor is executed. The
base keyword can be used with or without parameters. Any parameters to the constructor can be used as
parameters to base , or as part of an expression. For more information, see base.
In a derived class, if a base-class constructor is not called explicitly by using the base keyword, the parameterless
constructor, if there is one, is called implicitly. This means that the following constructor declarations are effectively
the same:
If a base class does not offer a parameterless constructor, the derived class must make an explicit call to a base
constructor by using base .
A constructor can invoke another constructor in the same object by using the this keyword. Like base , this can
be used with or without parameters, and any parameters in the constructor are available as parameters to this ,
or as part of an expression. For example, the second constructor in the previous example can be rewritten using
this :
The use of the this keyword in the previous example causes this constructor to be called:
Constructors can be marked as public, private, protected, internal, protected internal or private protected. These
access modifiers define how users of the class can construct the class. For more information, see Access Modifiers.
A constructor can be declared static by using the static keyword. Static constructors are called automatically,
immediately before any static fields are accessed, and are generally used to initialize static class members. For
more information, see Static Constructors.
C# Language Specification
For more information, see Instance constructors and Static constructors in the C# Language Specification. The
language specification is the definitive source for C# syntax and usage.
See also
C# Programming Guide
Classes and Structs
Constructors
Finalizers
Instance Constructors (C# Programming Guide)
9/3/2020 • 4 minutes to read • Edit Online
Instance constructors are used to create and initialize any instance member variables when you use the new
expression to create an object of a class. To initialize a static class, or static variables in a non-static class, you
define a static constructor. For more information, see Static Constructors.
The following example shows an instance constructor:
class Coords
{
public int x, y;
// constructor
public Coords()
{
x = 0;
y = 0;
}
}
NOTE
For clarity, this class contains public fields. The use of public fields is not a recommended programming practice because it
allows any method anywhere in a program unrestricted and unverified access to an object's inner workings. Data members
should generally be private, and should be accessed only through class methods and properties.
This instance constructor is called whenever an object based on the Coords class is created. A constructor like this
one, which takes no arguments, is called a parameterless constructor. However, it is often useful to provide
additional constructors. For example, we can add a constructor to the Coords class that allows us to specify the
initial values for the data members:
This allows Coords objects to be created with default or specific initial values, like this:
If a class does not have a constructor, a parameterless constructor is automatically generated and default values
are used to initialize the object fields. For example, an int is initialized to 0. For information about the type default
values, see Default values of C# types. Therefore, because the Coords class parameterless constructor initializes
all data members to zero, it can be removed altogether without changing how the class works. A complete
example using multiple constructors is provided in Example 1 later in this topic, and an example of an
automatically generated constructor is provided in Example 2.
Instance constructors can also be used to call the instance constructors of base classes. The class constructor can
invoke the constructor of the base class through the initializer, as follows:
In this example, the Circle class passes values representing radius and height to the constructor provided by
Shape from which Circle is derived. A complete example using Shape and Circle appears in this topic as
Example 3.
Example 1
The following example demonstrates a class with two class constructors, one without arguments and one with
two arguments.
class Coords
{
public int x, y;
// Default constructor.
public Coords()
{
x = 0;
y = 0;
}
class MainClass
{
static void Main()
{
var p1 = new Coords();
var p2 = new Coords(5, 3);
class TestPerson
{
static void Main()
{
var person = new Person();
Notice that the default value of age is 0 and the default value of name is null .
Example 3
The following example demonstrates using the base class initializer. The Circle class is derived from the general
class Shape , and the Cylinder class is derived from the Circle class. The constructor on each derived class is
using its base class initializer.
abstract class Shape
{
public const double pi = Math.PI;
protected double x, y;
class TestShapes
{
static void Main()
{
double radius = 2.5;
double height = 3.0;
For more examples on invoking the base class constructors, see virtual, override, and base.
See also
C# Programming Guide
Classes and Structs
Constructors
Finalizers
static
Private Constructors (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
A private constructor is a special instance constructor. It is generally used in classes that contain static members
only. If a class has one or more private constructors and no public constructors, other classes (except nested
classes) cannot create instances of this class. For example:
class NLog
{
// Private Constructor:
private NLog() { }
The declaration of the empty constructor prevents the automatic generation of a parameterless constructor. Note
that if you do not use an access modifier with the constructor it will still be private by default. However, the private
modifier is usually used explicitly to make it clear that the class cannot be instantiated.
Private constructors are used to prevent creating instances of a class when there are no instance fields or methods,
such as the Math class, or when a method is called to obtain an instance of a class. If all the methods in the class
are static, consider making the complete class static. For more information see Static Classes and Static Class
Members.
Example
The following is an example of a class using a private constructor.
class TestCounter
{
static void Main()
{
// If you uncomment the following statement, it will generate
// an error because the constructor is inaccessible:
// Counter aCounter = new Counter(); // Error
Counter.currentCount = 100;
Counter.IncrementCount();
Console.WriteLine("New count: {0}", Counter.currentCount);
C# Language Specification
For more information, see Private constructors in the C# Language Specification. The language specification is the
definitive source for C# syntax and usage.
See also
C# Programming Guide
Classes and Structs
Constructors
Finalizers
private
public
Static Constructors (C# Programming Guide)
9/3/2020 • 4 minutes to read • Edit Online
A static constructor is used to initialize any static data, or to perform a particular action that needs to be
performed once only. It is called automatically before the first instance is created or any static members are
referenced.
class SimpleClass
{
// Static variable that must be initialized at run time.
static readonly long baseline;
Remarks
Static constructors have the following properties:
A static constructor does not take access modifiers or have parameters.
A class or struct can only have one static constructor.
Static constructors cannot be inherited or overloaded.
A static constructor cannot be called directly and is only meant to be called by the common language
runtime (CLR). It is invoked automatically.
The user has no control on when the static constructor is executed in the program.
A static constructor is called automatically to initialize the class before the first instance is created or any
static members are referenced. A static constructor will run before an instance constructor. A type's static
constructor is called when a static method assigned to an event or a delegate is invoked and not when it is
assigned. If static field variable initializers are present in the class of the static constructor, they will be
executed in the textual order in which they appear in the class declaration immediately prior to the
execution of the static constructor.
If you don't provide a static constructor to initialize static fields, all static fields are initialized to their default
value as listed in Default values of C# types.
If a static constructor throws an exception, the runtime will not invoke it a second time, and the type will
remain uninitialized for the lifetime of the application domain in which your program is running. Most
commonly, a TypeInitializationException exception is thrown when a static constructor is unable to
instantiate a type or for an unhandled exception occurring within a static constructor. For implicit static
constructors that are not explicitly defined in source code, troubleshooting may require inspection of the
intermediate language (IL) code.
The presence of a static constructor prevents the addition of the BeforeFieldInit type attribute. This limits
runtime optimization.
A field declared as static readonly may only be assigned as part of its declaration or in a static
constructor. When an explicit static constructor is not required, initialize static fields at declaration, rather
than through a static constructor for better runtime optimization.
NOTE
Though not directly accessible, the presence of an explicit static constructor should be documented to assist with
troubleshooting initialization exceptions.
Usage
A typical use of static constructors is when the class is using a log file and the constructor is used to write
entries to this file.
Static constructors are also useful when creating wrapper classes for unmanaged code, when the
constructor can call the LoadLibrary method.
Static constructors are also a convenient place to enforce run-time checks on the type parameter that
cannot be checked at compile time via constraints (Type parameter constraints).
Example
In this example, class Bus has a static constructor. When the first instance of Bus is created ( bus1 ), the static
constructor is invoked to initialize the class. The sample output verifies that the static constructor runs only one
time, even though two instances of Bus are created, and that it runs before the instance constructor runs.
// Instance constructor.
public Bus(int routeNum)
{
RouteNumber = routeNum;
Console.WriteLine("Bus #{0} is created.", RouteNumber);
}
// Instance method.
public void Drive()
{
TimeSpan elapsedTime = DateTime.Now - globalStartTime;
class TestBus
{
static void Main()
{
// The creation of this instance activates the static constructor.
Bus bus1 = new Bus(71);
C# language specification
For more information, see the Static constructors section of the C# language specification.
See also
C# Programming Guide
Classes and Structs
Constructors
Static Classes and Static Class Members
Finalizers
Constructor Design Guidelines
Security Warning - CA2121: Static constructors should be private
How to write a copy constructor (C# Programming
Guide)
9/3/2020 • 2 minutes to read • Edit Online
C# doesn't provide a copy constructor for objects, but you can write one yourself.
Example
In the following example, the Person class defines a copy constructor that takes, as its argument, an instance of
Person . The values of the properties of the argument are assigned to the properties of the new instance of Person
. The code contains an alternative copy constructor that sends the Name and Age properties of the instance that
you want to copy to the instance constructor of the class.
class Person
{
// Copy constructor.
public Person(Person previousPerson)
{
Name = previousPerson.Name;
Age = previousPerson.Age;
}
// Instance constructor.
public Person(string name, int age)
{
Name = name;
Age = age;
}
class TestPerson
{
static void Main()
{
// Create a Person object by using the instance constructor.
Person person1 = new Person("George", 40);
// Show details to verify that the name and age fields are distinct.
Console.WriteLine(person1.Details());
Console.WriteLine(person2.Details());
See also
ICloneable
C# Programming Guide
Classes and Structs
Constructors
Finalizers
Finalizers (C# Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
Finalizers (which are also called destructors ) are used to perform any necessary final clean-up when a class
instance is being collected by the garbage collector.
Remarks
Finalizers cannot be defined in structs. They are only used with classes.
A class can only have one finalizer.
Finalizers cannot be inherited or overloaded.
Finalizers cannot be called. They are invoked automatically.
A finalizer does not take modifiers or have parameters.
For example, the following is a declaration of a finalizer for the Car class.
class Car
{
~Car() // finalizer
{
// cleanup statements...
}
}
A finalizer can also be implemented as an expression body definition, as the following example shows.
using System;
The finalizer implicitly calls Finalize on the base class of the object. Therefore, a call to a finalizer is implicitly
translated to the following code:
This design means that the Finalize method is called recursively for all instances in the inheritance chain,
from the most-derived to the least-derived.
NOTE
Empty finalizers should not be used. When a class contains a finalizer, an entry is created in the Finalize queue. When
the finalizer is called, the garbage collector is invoked to process the queue. An empty finalizer just causes a needless loss
of performance.
The programmer has no control over when the finalizer is called; the garbage collector decides when to call it.
The garbage collector checks for objects that are no longer being used by the application. If it considers an
object eligible for finalization, it calls the finalizer (if any) and reclaims the memory used to store the object.
In .NET Framework applications (but not in .NET Core applications), finalizers are also called when the program
exits.
It's possible to force garbage collection by calling Collect, but most of the time, this call should be avoided
because it may create performance issues.
Example
The following example creates three classes that make a chain of inheritance. The class First is the base class,
Second is derived from First , and Third is derived from Second . All three have finalizers. In Main , an
instance of the most-derived class is created. When the program runs, notice that the finalizers for the three
classes are called automatically, and in order, from the most-derived to the least-derived.
class First
{
~First()
{
System.Diagnostics.Trace.WriteLine("First's destructor is called.");
}
}
class TestDestructors
{
static void Main()
{
Third t = new Third();
}
}
/* Output (to VS Output Window):
Third's destructor is called.
Second's destructor is called.
First's destructor is called.
*/
C# language specification
For more information, see the Destructors section of the C# language specification.
See also
IDisposable
C# Programming Guide
Constructors
Garbage Collection
Object and Collection Initializers (C# Programming
Guide)
9/3/2020 • 8 minutes to read • Edit Online
C# lets you instantiate an object or collection and perform member assignments in a single statement.
Object initializers
Object initializers let you assign values to any accessible fields or properties of an object at creation time
without having to invoke a constructor followed by lines of assignment statements. The object initializer syntax
enables you to specify arguments for a constructor or omit the arguments (and parentheses syntax). The
following example shows how to use an object initializer with a named type, Cat and how to invoke the
parameterless constructor. Note the use of auto-implemented properties in the Cat class. For more
information, see Auto-Implemented Properties.
public Cat()
{
}
The object initializers syntax allows you to create an instance, and after that it assigns the newly created object,
with its assigned properties, to the variable in the assignment.
Starting with C# 6, object initializers can set indexers, in addition to assigning fields and properties. Consider
this basic Matrix class:
[1, 0] = 0.0,
[1, 1] = 1.0,
[1, 2] = 0.0,
[2, 0] = 0.0,
[2, 1] = 0.0,
[2, 2] = 1.0,
};
Any accessible indexer that contains an accessible setter can be used as one of the expressions in an object
initializer, regardless of the number or types of arguments. The index arguments form the left side of the
assignment, and the value is the right side of the expression. For example, these are all valid if IndexersExample
has the appropriate indexers:
For the preceding code to compile, the IndexersExample type must have the following members:
Anonymous types enable the select clause in a LINQ query expression to transform objects of the original
sequence into objects whose value and shape may differ from the original. This is useful if you want to store
only a part of the information from each object in a sequence. In the following example, assume that a product
object ( p ) contains many fields and methods, and that you are only interested in creating a sequence of
objects that contain the product name and the unit price.
var productInfos =
from p in products
select new { p.ProductName, p.UnitPrice };
When this query is executed, the productInfos variable will contain a sequence of objects that can be accessed
in a foreach statement as shown in this example:
foreach(var p in productInfos){...}
Each object in the new anonymous type has two public properties that receive the same names as the
properties or fields in the original object. You can also rename a field when you are creating an anonymous
type; the following example renames the UnitPrice field to Price .
Collection initializers
Collection initializers let you specify one or more element initializers when you initialize a collection type that
implements IEnumerable and has Add with the appropriate signature as an instance method or an extension
method. The element initializers can be a simple value, an expression, or an object initializer. By using a
collection initializer, you do not have to specify multiple calls; the compiler adds the calls automatically.
The following example shows two simple collection initializers:
The following collection initializer uses object initializers to initialize objects of the Cat class defined in a
previous example. Note that the individual object initializers are enclosed in braces and separated by commas.
You can specify null as an element in a collection initializer if the collection's Add method allows it.
You can specify indexed elements if the collection supports read / write indexing.
The preceding sample generates code that calls the Item[TKey] to set the values. Before C# 6, you could
initialize dictionaries and other associative containers using the following syntax. Notice that instead of indexer
syntax, with parentheses and an assignment, it uses an object with multiple values:
This initializer example calls Add(TKey, TValue) to add the three items into the dictionary. These two different
ways to initialize associative collections have slightly different behavior because of the method calls the
compiler generates. Both variants work with the Dictionary class. Other types may only support one or the
other based on their public API.
Examples
The following example combines the concepts of object and collection initializers.
public class InitializationSample
{
public class Cat
{
// Auto-implemented properties.
public int Age { get; set; }
public string Name { get; set; }
public Cat() { }
// Display results.
System.Console.WriteLine(cat.Name);
The following example shows an object that implements IEnumerable and contains an Add method with
multiple parameters, It uses a collection initializer with multiple elements per item in the list that correspond to
the signature of the Add method.
public class FullExample
{
class FormattedAddresses : IEnumerable<string>
{
private List<string> internalList = new List<string>();
public IEnumerator<string> GetEnumerator() => internalList.GetEnumerator();
Console.WriteLine("Address Entries:");
/*
* Prints:
Address Entries:
John Doe
123 Street
Topeka, KS 00000
Jane Smith
456 Street
Topeka, KS 00000
*/
}
Add methods can use the params keyword to take a variable number of arguments, as shown in the following
example. This example also demonstrates the custom implementation of an indexer to initialize a collection
using indexes.
public void Add(TKey key, params TValue[] values) => Add(key, (IEnumerable<TValue>)values);
storedValues.AddRange(values);
}
}
/*
* Prints:
Using second multi-valued dictionary created with a collection initializer using indexing:
Using third multi-valued dictionary created with a collection initializer using indexing:
See also
C# Programming Guide
LINQ in C#
Anonymous Types
How to initialize objects by using an object initializer
(C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
You can use object initializers to initialize type objects in a declarative manner without explicitly invoking a
constructor for the type.
The following examples show how to use object initializers with named objects. The compiler processes object
initializers by first accessing the default instance constructor and then processing the member initializations.
Therefore, if the parameterless constructor is declared as private in the class, object initializers that require public
access will fail.
You must use an object initializer if you're defining an anonymous type. For more information, see How to return
subsets of element properties in a query.
Example
The following example shows how to initialize a new StudentName type by using object initializers. This example
sets properties in the StudentName type:
Console.WriteLine(student1.ToString());
Console.WriteLine(student2.ToString());
Console.WriteLine(student2.ToString());
Console.WriteLine(student3.ToString());
Console.WriteLine(student4.ToString());
}
// Output:
// Craig 0
// Craig 0
// 183
// Craig 116
// Properties.
public string FirstName { get; set; }
public string LastName { get; set; }
public int ID { get; set; }
Object initializers can be used to set indexers in an object. The following example defines a BaseballTeam class that
uses an indexer to get and set players at different positions. The initializer can assign players, based on the
abbreviation for the position, or the number used for each position baseball scorecards:
public class HowToIndexInitializer
{
public class BaseballTeam
{
private string[] players = new string[9];
private readonly List<string> positionAbbreviations = new List<string>
{
"P", "C", "1B", "2B", "3B", "SS", "LF", "CF", "RF"
};
Console.WriteLine(team["2B"]);
}
}
See also
C# Programming Guide
Object and Collection Initializers
How to initialize a dictionary with a collection
initializer (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
A Dictionary<TKey,TValue> contains a collection of key/value pairs. Its Add method takes two parameters, one for
the key and one for the value. One way to initialize a Dictionary<TKey,TValue>, or any collection whose Add
method takes multiple parameters, is to enclose each set of parameters in braces as shown in the following
example. Another option is to use an index initializer, also shown in the following example.
Example
In the following code example, a Dictionary<TKey,TValue> is initialized with instances of type StudentName . The
first initialization uses the Add method with two arguments. The compiler generates a call to Add for each of the
pairs of int keys and StudentName values. The second uses a public read / write indexer method of the
Dictionary class:
Note the two pairs of braces in each element of the collection in the first declaration. The innermost braces enclose
the object initializer for the StudentName , and the outermost braces enclose the initializer for the key/value pair that
will be added to the students Dictionary<TKey,TValue>. Finally, the whole collection initializer for the dictionary is
enclosed in braces. In the second initialization, the left side of the assignment is the key and the right side is the
value, using an object initializer for StudentName .
See also
C# Programming Guide
Object and Collection Initializers
Nested Types (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
A type defined within a class, struct, or interface is called a nested type. For example
Regardless of whether the outer type is a class, interface, or struct, nested types default to private; they are
accessible only from their containing type. In the previous example, the Nested class is inaccessible to external
types.
You can also specify an access modifier to define the accessibility of a nested type, as follows:
Nested types of a class can be public, protected, internal, protected internal, private or private protected.
However, defining a protected , protected internal or private protected nested class inside a sealed class
generates compiler warning CS0628, "new protected member declared in sealed class."
Nested types of a struct can be public, internal, or private.
The following example makes the Nested class public:
The nested, or inner, type can access the containing, or outer, type. To access the containing type, pass it as an
argument to the constructor of the nested type. For example:
public Nested()
{
}
public Nested(Container parent)
{
this.parent = parent;
}
}
}
A nested type has access to all of the members that are accessible to its containing type. It can access private and
protected members of the containing type, including any inherited protected members.
In the previous declaration, the full name of class Nested is Container.Nested . This is the name used to create a
new instance of the nested class, as follows:
See also
C# Programming Guide
Classes and Structs
Access Modifiers
Constructors
Partial Classes and Methods (C# Programming
Guide)
9/3/2020 • 6 minutes to read • Edit Online
It is possible to split the definition of a class, a struct, an interface or a method over two or more source files. Each
source file contains a section of the type or method definition, and all parts are combined when the application is
compiled.
Partial Classes
There are several situations when splitting a class definition is desirable:
When working on large projects, spreading a class over separate files enables multiple programmers to
work on it at the same time.
When working with automatically generated source, code can be added to the class without having to
recreate the source file. Visual Studio uses this approach when it creates Windows Forms, Web service
wrapper code, and so on. You can create code that uses these classes without having to modify the file
created by Visual Studio.
To split a class definition, use the partial keyword modifier, as shown here:
The partial keyword indicates that other parts of the class, struct, or interface can be defined in the namespace.
All the parts must use the partial keyword. All the parts must be available at compile time to form the final type.
All the parts must have the same accessibility, such as public , private , and so on.
If any part is declared abstract, then the whole type is considered abstract. If any part is declared sealed, then the
whole type is considered sealed. If any part declares a base type, then the whole type inherits that class.
All the parts that specify a base class must agree, but parts that omit a base class still inherit the base type. Parts
can specify different base interfaces, and the final type implements all the interfaces listed by all the partial
declarations. Any class, struct, or interface members declared in a partial definition are available to all the other
parts. The final type is the combination of all the parts at compile time.
NOTE
The partial modifier is not available on delegate or enumeration declarations.
The following example shows that nested types can be partial, even if the type they are nested within is not partial
itself.
class Container
{
partial class Nested
{
void Test() { }
}
partial class Nested
{
void Test2() { }
}
}
At compile time, attributes of partial-type definitions are merged. For example, consider the following declarations:
[SerializableAttribute]
partial class Moon { }
[ObsoleteAttribute]
partial class Moon { }
[SerializableAttribute]
[ObsoleteAttribute]
class Moon { }
Restrictions
There are several rules to follow when you are working with partial class definitions:
All partial-type definitions meant to be parts of the same type must be modified with partial . For
example, the following class declarations generate an error:
public partial class A { }
//public class A { } // Error, must also be marked partial
The partial modifier can only appear immediately before the keywords class , struct , or interface .
Nested partial types are allowed in partial-type definitions as illustrated in the following example:
All partial-type definitions meant to be parts of the same type must be defined in the same assembly and
the same module (.exe or .dll file). Partial definitions cannot span multiple modules.
The class name and generic-type parameters must match on all partial-type definitions. Generic types can
be partial. Each partial declaration must use the same parameter names in the same order.
The following keywords on a partial-type definition are optional, but if present on one partial-type
definition, cannot conflict with the keywords specified on another partial definition for the same type:
public
private
protected
internal
abstract
sealed
base class
new modifier (nested parts)
generic constraints
For more information, see Constraints on Type Parameters.
Example 1
Description
In the following example, the fields and the constructor of the class, Coords , are declared in one partial class
definition, and the member, PrintCoords , is declared in another partial class definition.
Code
public partial class Coords
{
private int x;
private int y;
class TestCoords
{
static void Main()
{
Coords myCoords = new Coords(10, 15);
myCoords.PrintCoords();
Example 2
Description
The following example shows that you can also develop partial structs and interfaces.
Code
partial struct S1
{
void Struct_Test() { }
}
partial struct S1
{
void Struct_Test2() { }
}
Partial Methods
A partial class or struct may contain a partial method. One part of the class contains the signature of the method.
An optional implementation may be defined in the same part or another part. If the implementation is not
supplied, then the method and all calls to the method are removed at compile time.
Partial methods enable the implementer of one part of a class to define a method, similar to an event. The
implementer of the other part of the class can decide whether to implement the method or not. If the method is
not implemented, then the compiler removes the method signature and all calls to the method. The calls to the
method, including any results that would occur from evaluation of arguments in the calls, have no effect at run
time. Therefore, any code in the partial class can freely use a partial method, even if the implementation is not
supplied. No compile-time or run-time errors will result if the method is called but not implemented.
Partial methods are especially useful as a way to customize generated code. They allow for a method name and
signature to be reserved, so that generated code can call the method but the developer can decide whether to
implement the method. Much like partial classes, partial methods enable code created by a code generator and
code created by a human developer to work together without run-time costs.
A partial method declaration consists of two parts: the definition, and the implementation. These may be in
separate parts of a partial class, or in the same part. If there is no implementation declaration, then the compiler
optimizes away both the defining declaration and all calls to the method.
// Definition in file1.cs
partial void onNameChanged();
// Implementation in file2.cs
partial void onNameChanged()
{
// method body
}
Partial method declarations must begin with the contextual keyword partial and the method must return
void.
Partial methods can have in or ref but not out parameters.
Partial methods are implicitly private, and therefore they cannot be virtual.
Partial methods cannot be extern, because the presence of the body determines whether they are defining
or implementing.
Partial methods can have static and unsafe modifiers.
Partial methods can be generic. Constraints are put on the defining partial method declaration, and may
optionally be repeated on the implementing one. Parameter and type parameter names do not have to be
the same in the implementing declaration as in the defining one.
You can make a delegate to a partial method that has been defined and implemented, but not to a partial
method that has only been defined.
C# Language Specification
For more information, see Partial types in the C# Language Specification. The language specification is the
definitive source for C# syntax and usage.
See also
C# Programming Guide
Classes
Structure types
Interfaces
partial (Type)
Anonymous Types (C# Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
Anonymous types provide a convenient way to encapsulate a set of read-only properties into a single object
without having to explicitly define a type first. The type name is generated by the compiler and is not
available at the source code level. The type of each property is inferred by the compiler.
You create anonymous types by using the new operator together with an object initializer. For more
information about object initializers, see Object and Collection Initializers.
The following example shows an anonymous type that is initialized with two properties named Amount and
Message .
// Rest the mouse pointer over v.Amount and v.Message in the following
// statement to verify that their inferred types are int and string.
Console.WriteLine(v.Amount + v.Message);
Anonymous types typically are used in the select clause of a query expression to return a subset of the
properties from each object in the source sequence. For more information about queries, see LINQ in C#.
Anonymous types contain one or more public read-only properties. No other kinds of class members, such
as methods or events, are valid. The expression that is used to initialize a property cannot be null , an
anonymous function, or a pointer type.
The most common scenario is to initialize an anonymous type with properties from another type. In the
following example, assume that a class exists that is named Product . Class Product includes Color and
Price properties, together with other properties that you are not interested in. Variable products is a
collection of Product objects. The anonymous type declaration starts with the new keyword. The
declaration initializes a new type that uses only two properties from Product . This causes a smaller amount
of data to be returned in the query.
If you do not specify member names in the anonymous type, the compiler gives the anonymous type
members the same name as the property being used to initialize them. You must provide a name for a
property that is being initialized with an expression, as shown in the previous example. In the following
example, the names of the properties of the anonymous type are Color and Price .
var productQuery =
from prod in products
select new { prod.Color, prod.Price };
Typically, when you use an anonymous type to initialize a variable, you declare the variable as an implicitly
typed local variable by using var. The type name cannot be specified in the variable declaration because only
the compiler has access to the underlying name of the anonymous type. For more information about var ,
see Implicitly Typed Local Variables.
You can create an array of anonymously typed elements by combining an implicitly typed local variable and
an implicitly typed array, as shown in the following example.
var anonArray = new[] { new { name = "apple", diam = 4 }, new { name = "grape", diam = 1 }};
Remarks
Anonymous types are class types that derive directly from object, and that cannot be cast to any type except
object. The compiler provides a name for each anonymous type, although your application cannot access it.
From the perspective of the common language runtime, an anonymous type is no different from any other
reference type.
If two or more anonymous object initializers in an assembly specify a sequence of properties that are in the
same order and that have the same names and types, the compiler treats the objects as instances of the
same type. They share the same compiler-generated type information.
You cannot declare a field, a property, an event, or the return type of a method as having an anonymous
type. Similarly, you cannot declare a formal parameter of a method, property, constructor, or indexer as
having an anonymous type. To pass an anonymous type, or a collection that contains anonymous types, as
an argument to a method, you can declare the parameter as type object. However, doing this defeats the
purpose of strong typing. If you must store query results or pass them outside the method boundary,
consider using an ordinary named struct or class instead of an anonymous type.
Because the Equals and GetHashCode methods on anonymous types are defined in terms of the Equals and
GetHashCode methods of the properties, two instances of the same anonymous type are equal only if all
their properties are equal.
See also
C# Programming Guide
Object and Collection Initializers
Getting Started with LINQ in C#
LINQ in C#
How to return subsets of element properties in a
query (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
Use an anonymous type in a query expression when both of these conditions apply:
You want to return only some of the properties of each source element.
You do not have to store the query results outside the scope of the method in which the query is executed.
If you only want to return one property or field from each source element, then you can just use the dot operator
in the select clause. For example, to return only the ID of each student , write the select clause as follows:
select student.ID;
Example
The following example shows how to use an anonymous type to return only a subset of the properties of each
source element that matches the specified condition.
Note that the anonymous type uses the source element's names for its properties if no names are specified. To give
new names to the properties in the anonymous type, write the select statement as follows:
If you try this in the previous example, then the Console.WriteLine statement must also change:
Console.WriteLine(student.First + " " + student.Last);
See also
C# Programming Guide
Anonymous Types
LINQ in C#
Interfaces (C# Programming Guide)
9/3/2020 • 4 minutes to read • Edit Online
An interface contains definitions for a group of related functionalities that a non-abstract class or a struct
must implement. An interface may define static methods, which must have an implementation. Beginning
with C# 8.0, an interface may define a default implementation for members. An interface may not declare
instance data such as fields, auto-implemented properties, or property-like events.
By using interfaces, you can, for example, include behavior from multiple sources in a class. That capability is
important in C# because the language doesn't support multiple inheritance of classes. In addition, you must
use an interface if you want to simulate inheritance for structs, because they can't actually inherit from
another struct or class.
You define an interface by using the interface keyword as the following example shows.
interface IEquatable<T>
{
bool Equals(T obj);
}
The name of an interface must be a valid C# identifier name. By convention, interface names begin with a
capital I .
Any class or struct that implements the IEquatable<T> interface must contain a definition for an Equals
method that matches the signature that the interface specifies. As a result, you can count on a class that
implements IEquatable<T> to contain an Equals method with which an instance of the class can determine
whether it's equal to another instance of the same class.
The definition of IEquatable<T> doesn't provide an implementation for Equals . A class or struct can
implement multiple interfaces, but a class can only inherit from a single class.
For more information about abstract classes, see Abstract and Sealed Classes and Class Members.
Interfaces can contain instance methods, properties, events, indexers, or any combination of those four
member types. Interfaces may contain static constructors, fields, constants, or operators. For links to
examples, see Related Sections. An interface can't contain instance fields, instance constructors, or finalizers.
Interface members are public by default.
To implement an interface member, the corresponding member of the implementing class must be public,
non-static, and have the same name and signature as the interface member.
When a class or struct implements an interface, the class or struct must provide an implementation for all of
the members that the interface declares but doesn't provide a default implementation for. However, if a base
class implements an interface, any class that's derived from the base class inherits that implementation.
The following example shows an implementation of the IEquatable<T> interface. The implementing class,
Car , must provide an implementation of the Equals method.
public class Car : IEquatable<Car>
{
public string Make {get; set;}
public string Model { get; set; }
public string Year { get; set; }
Properties and indexers of a class can define extra accessors for a property or indexer that's defined in an
interface. For example, an interface might declare a property that has a get accessor. The class that
implements the interface can declare the same property with both a get and set accessor. However, if the
property or indexer uses explicit implementation, the accessors must match. For more information about
explicit implementation, see Explicit Interface Implementation and Interface Properties.
Interfaces can inherit from one or more interfaces. The derived interface inherits the members from its base
interfaces. A class that implements a derived interface must implement all members in the derived interface,
including all members of the derived interface's base interfaces. That class may be implicitly converted to the
derived interface or any of its base interfaces. A class might include an interface multiple times through base
classes that it inherits or through interfaces that other interfaces inherit. However, the class can provide an
implementation of an interface only one time and only if the class declares the interface as part of the
definition of the class ( class ClassName : InterfaceName ). If the interface is inherited because you inherited a
base class that implements the interface, the base class provides the implementation of the members of the
interface. However, the derived class can reimplement any virtual interface members instead of using the
inherited implementation. When interfaces declare a default implementation of a method, any class
implementing that interface inherits that implementation. Implementations defined in interfaces are virtual
and the implementing class may override that implementation.
A base class can also implement interface members by using virtual members. In that case, a derived class
can change the interface behavior by overriding the virtual members. For more information about virtual
members, see Polymorphism.
Interfaces summary
An interface has the following properties:
An interface is typically like an abstract base class with only abstract members. Any class or struct that
implements the interface must implement all its members. Optionally, an interface may define default
implementations for some or all of its members. For more information, see default interface methods.
An interface can't be instantiated directly. Its members are implemented by any class or struct that
implements the interface.
A class or struct can implement multiple interfaces. A class can inherit a base class and also implement one
or more interfaces.
Related Sections
Interface Properties
Indexers in Interfaces
How to implement interface events
Classes and Structs
Inheritance
Interfaces
Methods
Polymorphism
Abstract and Sealed Classes and Class Members
Properties
Events
Indexers
See also
C# Programming Guide
Inheritance
Identifier names
Explicit Interface Implementation (C# Programming
Guide)
9/3/2020 • 2 minutes to read • Edit Online
If a class implements two interfaces that contain a member with the same signature, then implementing that
member on the class will cause both interfaces to use that member as their implementation. In the following
example, all the calls to Paint invoke the same method. This first sample defines the types:
When two interface members don't perform the same function, it leads to an incorrect implementation of one or
both of the interfaces. It's possible to implement an interface member explicitly—creating a class member that is
only called through the interface, and is specific to that interface. Name the class member with the name of the
interface and a period. For example:
public class SampleClass : IControl, ISurface
{
void IControl.Paint()
{
System.Console.WriteLine("IControl.Paint");
}
void ISurface.Paint()
{
System.Console.WriteLine("ISurface.Paint");
}
}
The class member IControl.Paint is only available through the IControl interface, and ISurface.Paint is only
available through ISurface . Both method implementations are separate, and neither are available directly on the
class. For example:
IControl c = obj;
c.Paint(); // Calls IControl.Paint on SampleClass.
ISurface s = obj;
s.Paint(); // Calls ISurface.Paint on SampleClass.
// Output:
// IControl.Paint
// ISurface.Paint
Explicit implementation is also used to resolve cases where two interfaces each declare different members of the
same name such as a property and a method. To implement both interfaces, a class has to use explicit
implementation either for the property P , or the method P , or both, to avoid a compiler error. For example:
interface ILeft
{
int P { get;}
}
interface IRight
{
int P();
}
Beginning with C# 8.0, you can define an implementation for members declared in an interface. If a class inherits a
method implementation from an interface, that method is only accessible through a reference of the interface
type. The inherited member doesn't appear as part of the public interface. The following sample defines a default
implementation for an interface method:
public interface IControl
{
void Paint() => Console.WriteLine("Default Paint method");
}
public class SampleClass : IControl
{
// Paint() is inherited from IControl.
}
Any class that implements the IControl interface can override the default Paint method, either as a public
method, or as an explicit interface implementation.
See also
C# Programming Guide
Classes and Structs
Interfaces
Inheritance
How to explicitly implement interface members (C#
Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
This example declares an interface, IDimensions , and a class, Box , which explicitly implements the interface
members GetLength and GetWidth . The members are accessed through the interface instance dimensions .
Example
interface IDimensions
{
float GetLength();
float GetWidth();
}
Robust Programming
Notice that the following lines, in the Main method, are commented out because they would produce
compilation errors. An interface member that is explicitly implemented cannot be accessed from a class
instance:
Notice also that the following lines, in the Main method, successfully print out the dimensions of the box
because the methods are being called from an instance of the interface:
System.Console.WriteLine("Length: {0}", dimensions.GetLength());
System.Console.WriteLine("Width: {0}", dimensions.GetWidth());
See also
C# Programming Guide
Classes and Structs
Interfaces
How to explicitly implement members of two interfaces
How to explicitly implement members of two
interfaces (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
Explicit interface implementation also allows the programmer to implement two interfaces that have the same
member names and give each interface member a separate implementation. This example displays the dimensions
of a box in both metric and English units. The Box class implements two interfaces IEnglishDimensions and
IMetricDimensions, which represent the different measurement systems. Both interfaces have identical member
names, Length and Width.
Example
// Declare the English units interface:
interface IEnglishDimensions
{
float Length();
float Width();
}
Robust Programming
If you want to make the default measurements in English units, implement the methods Length and Width
normally, and explicitly implement the Length and Width methods from the IMetricDimensions interface:
// Normal implementation:
public float Length() => lengthInches;
public float Width() => widthInches;
// Explicit implementation:
float IMetricDimensions.Length() => lengthInches * 2.54f;
float IMetricDimensions.Width() => widthInches * 2.54f;
In this case, you can access the English units from the class instance and access the metric units from the interface
instance:
See also
C# Programming Guide
Classes and Structs
Interfaces
How to explicitly implement interface members
Delegates (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
A delegate is a type that represents references to methods with a particular parameter list and return type.
When you instantiate a delegate, you can associate its instance with any method with a compatible signature
and return type. You can invoke (or call) the method through the delegate instance.
Delegates are used to pass methods as arguments to other methods. Event handlers are nothing more than
methods that are invoked through delegates. You create a custom method, and a class such as a windows
control can call your method when a certain event occurs. The following example shows a delegate declaration:
Any method from any accessible class or struct that matches the delegate type can be assigned to the delegate.
The method can be either static or an instance method. This makes it possible to programmatically change
method calls, and also plug new code into existing classes.
NOTE
In the context of method overloading, the signature of a method does not include the return value. But in the context of
delegates, the signature does include the return value. In other words, a method must have the same return type as the
delegate.
This ability to refer to a method as a parameter makes delegates ideal for defining callback methods. For
example, a reference to a method that compares two objects could be passed as an argument to a sort
algorithm. Because the comparison code is in a separate procedure, the sort algorithm can be written in a more
general way.
Delegates Overview
Delegates have the following properties:
Delegates are similar to C++ function pointers, but delegates are fully object-oriented, and unlike C++
pointers to member functions, delegates encapsulate both an object instance and a method.
Delegates allow methods to be passed as parameters.
Delegates can be used to define callback methods.
Delegates can be chained together; for example, multiple methods can be called on a single event.
Methods do not have to match the delegate type exactly. For more information, see Using Variance in
Delegates.
C# version 2.0 introduced the concept of anonymous methods, which allow code blocks to be passed as
parameters in place of a separately defined method. C# 3.0 introduced lambda expressions as a more
concise way of writing inline code blocks. Both anonymous methods and lambda expressions (in certain
contexts) are compiled to delegate types. Together, these features are now known as anonymous
functions. For more information about lambda expressions, see Lambda expressions.
In This Section
Using Delegates
When to Use Delegates Instead of Interfaces (C# Programming Guide)
Delegates with Named vs. Anonymous Methods
Using Variance in Delegates
How to combine delegates (Multicast Delegates)
How to declare, instantiate, and use a delegate
C# Language Specification
For more information, see Delegates in the C# Language Specification. The language specification is the
definitive source for C# syntax and usage.
See also
Delegate
C# Programming Guide
Events
Using Delegates (C# Programming Guide)
9/3/2020 • 5 minutes to read • Edit Online
A delegate is a type that safely encapsulates a method, similar to a function pointer in C and C++. Unlike C function
pointers, delegates are object-oriented, type safe, and secure. The type of a delegate is defined by the name of the
delegate. The following example declares a delegate named Del that can encapsulate a method that takes a string
as an argument and returns void:
A delegate object is normally constructed by providing the name of the method the delegate will wrap, or with an
anonymous function. Once a delegate is instantiated, a method call made to the delegate will be passed by the
delegate to that method. The parameters passed to the delegate by the caller are passed to the method, and the
return value, if any, from the method is returned to the caller by the delegate. This is known as invoking the
delegate. An instantiated delegate can be invoked as if it were the wrapped method itself. For example:
Delegate types are derived from the Delegate class in .NET. Delegate types are sealed—they cannot be derived from
— and it is not possible to derive custom classes from Delegate. Because the instantiated delegate is an object, it
can be passed as a parameter, or assigned to a property. This allows a method to accept a delegate as a parameter,
and call the delegate at some later time. This is known as an asynchronous callback, and is a common method of
notifying a caller when a long process has completed. When a delegate is used in this fashion, the code using the
delegate does not need any knowledge of the implementation of the method being used. The functionality is
similar to the encapsulation interfaces provide.
Another common use of callbacks is defining a custom comparison method and passing that delegate to a sort
method. It allows the caller's code to become part of the sort algorithm. The following example method uses the
Del type as a parameter:
You can then pass the delegate created above to that method:
MethodWithCallback(1, 2, handler);
and receive the following output to the console:
Using the delegate as an abstraction, MethodWithCallback does not need to call the console directly—it does not
have to be designed with a console in mind. What MethodWithCallback does is simply prepare a string and pass the
string to another method. This is especially powerful since a delegated method can use any number of parameters.
When a delegate is constructed to wrap an instance method, the delegate references both the instance and the
method. A delegate has no knowledge of the instance type aside from the method it wraps, so a delegate can refer
to any type of object as long as there is a method on that object that matches the delegate signature. When a
delegate is constructed to wrap a static method, it only references the method. Consider the following declarations:
Along with the static DelegateMethod shown previously, we now have three methods that can be wrapped by a
Del instance.
A delegate can call more than one method when invoked. This is referred to as multicasting. To add an extra
method to the delegate's list of methods—the invocation list—simply requires adding two delegates using the
addition or addition assignment operators ('+' or '+='). For example:
At this point allMethodsDelegate contains three methods in its invocation list— Method1 , Method2 , and
DelegateMethod . The original three delegates, d1 , d2 , and d3 , remain unchanged. When allMethodsDelegate is
invoked, all three methods are called in order. If the delegate uses reference parameters, the reference is passed
sequentially to each of the three methods in turn, and any changes by one method are visible to the next method.
When any of the methods throws an exception that is not caught within the method, that exception is passed to the
caller of the delegate and no subsequent methods in the invocation list are called. If the delegate has a return value
and/or out parameters, it returns the return value and parameters of the last method invoked. To remove a method
from the invocation list, use the subtraction or subtraction assignment operators ( - or -= ). For example:
//remove Method1
allMethodsDelegate -= d1;
Because delegate types are derived from System.Delegate , the methods and properties defined by that class can be
called on the delegate. For example, to find the number of methods in a delegate's invocation list, you may write:
int invocationCount = d1.GetInvocationList().GetLength(0);
Delegates with more than one method in their invocation list derive from MulticastDelegate, which is a subclass of
System.Delegate . The above code works in either case because both classes support GetInvocationList .
Multicast delegates are used extensively in event handling. Event source objects send event notifications to
recipient objects that have registered to receive that event. To register for an event, the recipient creates a method
designed to handle the event, then creates a delegate for that method and passes the delegate to the event source.
The source calls the delegate when the event occurs. The delegate then calls the event handling method on the
recipient, delivering the event data. The delegate type for a given event is defined by the event source. For more,
see Events.
Comparing delegates of two different types assigned at compile-time will result in a compilation error. If the
delegate instances are statically of the type System.Delegate , then the comparison is allowed, but will return false
at run time. For example:
See also
C# Programming Guide
Delegates
Using Variance in Delegates
Variance in Delegates
Using Variance for Func and Action Generic Delegates
Events
Delegates with Named vs. Anonymous Methods (C#
Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
A delegate can be associated with a named method. When you instantiate a delegate by using a named method,
the method is passed as a parameter, for example:
// Declare a delegate.
delegate void Del(int x);
This is called using a named method. Delegates constructed with a named method can encapsulate either a static
method or an instance method. Named methods are the only way to instantiate a delegate in earlier versions of C#.
However, in a situation where creating a new method is unwanted overhead, C# enables you to instantiate a
delegate and immediately specify a code block that the delegate will process when it is called. The block can
contain either a lambda expression or an anonymous method. For more information, see Anonymous Functions.
Remarks
The method that you pass as a delegate parameter must have the same signature as the delegate declaration.
A delegate instance may encapsulate either static or instance method.
Although the delegate can use an out parameter, we do not recommend its use with multicast event delegates
because you cannot know which delegate will be called.
Example 1
The following is a simple example of declaring and using a delegate. Notice that both the delegate, Del , and the
associated method, MultiplyNumbers , have the same signature
// Declare a delegate
delegate void Del(int i, double j);
class MathClass
{
static void Main()
{
MathClass m = new MathClass();
Example 2
In the following example, one delegate is mapped to both static and instance methods and returns specific
information from each.
// Declare a delegate
delegate void Del();
class SampleClass
{
public void InstanceMethod()
{
Console.WriteLine("A message from the instance method.");
}
class TestSampleClass
{
static void Main()
{
var sc = new SampleClass();
See also
C# Programming Guide
Delegates
How to combine delegates (Multicast Delegates)
Events
How to combine delegates (Multicast Delegates) (C#
Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
This example demonstrates how to create multicast delegates. A useful property of delegate objects is that
multiple objects can be assigned to one delegate instance by using the + operator. The multicast delegate
contains a list of the assigned delegates. When the multicast delegate is called, it invokes the delegates in the list,
in order. Only delegates of the same type can be combined.
The - operator can be used to remove a component delegate from a multicast delegate.
Example
using System;
// Define a custom delegate that has a string parameter and returns void.
delegate void CustomDel(string s);
class TestClass
{
// Define two methods that have the same signature as CustomDel.
static void Hello(string s)
{
Console.WriteLine($" Hello, {s}!");
}
In C# 1.0 and later, delegates can be declared as shown in the following example.
// Declare a delegate.
delegate void Del(string str);
C# 2.0 provides a simpler way to write the previous declaration, as shown in the following example.
In C# 2.0 and later, it is also possible to use an anonymous method to declare and initialize a delegate, as shown in
the following example.
In C# 3.0 and later, delegates can also be declared and instantiated by using a lambda expression, as shown in the
following example.
The use of delegates promotes good separation of functionality between the bookstore database and the client
code. The client code has no knowledge of how the books are stored or how the bookstore code finds paperback
books. The bookstore code has no knowledge of what processing is performed on the paperback books after it
finds them.
Example
// A set of classes for handling a bookstore:
namespace Bookstore
{
using System.Collections;
Robust Programming
Declaring a delegate.
The following statement declares a new delegate type.
Each delegate type describes the number and types of the arguments, and the type of the return value of
methods that it can encapsulate. Whenever a new set of argument types or return value type is needed, a
new delegate type must be declared.
Instantiating a delegate.
After a delegate type has been declared, a delegate object must be created and associated with a particular
method. In the previous example, you do this by passing the PrintTitle method to the
ProcessPaperbackBooks method as in the following example:
bookDB.ProcessPaperbackBooks(PrintTitle);
This creates a new delegate object associated with the static method Test.PrintTitle . Similarly, the non-
static method AddBookToTotal on the object totaller is passed as in the following example:
bookDB.ProcessPaperbackBooks(totaller.AddBookToTotal);
processBook(b);
A delegate can be either called synchronously, as in this example, or asynchronously by using BeginInvoke
and EndInvoke methods.
See also
C# Programming Guide
Events
Delegates
Arrays (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
You can store multiple variables of the same type in an array data structure. You declare an array by specifying
the type of its elements. If you want the array to store elements of any type, you can specify object as its type. In
the unified type system of C#, all types, predefined and user-defined, reference types and value types, inherit
directly or indirectly from Object.
type[] arrayName;
Example
The following example creates single-dimensional, multidimensional, and jagged arrays:
class TestArraysClass
{
static void Main()
{
// Declare a single-dimensional array of 5 integers.
int[] array1 = new int[5];
// Alternative syntax.
int[] array3 = { 1, 2, 3, 4, 5, 6 };
// Set the values of the first array in the jagged array structure.
jaggedArray[0] = new int[4] { 1, 2, 3, 4 };
}
}
Array overview
An array has the following properties:
An array can be Single-Dimensional, Multidimensional or Jagged.
The number of dimensions and the length of each dimension are established when the array instance is
created. These values can't be changed during the lifetime of the instance.
The default values of numeric array elements are set to zero, and reference elements are set to null.
A jagged array is an array of arrays, and therefore its elements are reference types and are initialized to null .
Arrays are zero indexed: an array with n elements is indexed from 0 to n-1 .
Array elements can be of any type, including an array type.
Array types are reference types derived from the abstract base type Array. Since this type implements
IEnumerable and IEnumerable<T>, you can use foreach iteration on all arrays in C#.
Related sections
Arrays as Objects
Using foreach with Arrays
Passing Arrays as Arguments
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Programming Guide
Collections
Arrays as Objects (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
In C#, arrays are actually objects, and not just addressable regions of contiguous memory as in C and C++. Array is
the abstract base type of all array types. You can use the properties and other class members that Array has. An
example of this is using the Length property to get the length of an array. The following code assigns the length of
the numbers array, which is 5 , to a variable called lengthOfNumbers :
int[] numbers = { 1, 2, 3, 4, 5 };
int lengthOfNumbers = numbers.Length;
The Array class provides many other useful methods and properties for sorting, searching, and copying arrays.
Example
This example uses the Rank property to display the number of dimensions of an array.
class TestArraysClass
{
static void Main()
{
// Declare and initialize an array.
int[,] theArray = new int[5, 10];
System.Console.WriteLine("The array has {0} dimensions.", theArray.Rank);
}
}
// Output: The array has 2 dimensions.
See also
C# Programming Guide
Arrays
Single-Dimensional Arrays
Multidimensional Arrays
Jagged Arrays
Single-Dimensional Arrays (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
You create a single-dimensional array using the new operator specifying the array element type and the number
of elements. The following example declares an array of five integers:
This array contains the elements from array[0] to array[4] . The elements of the array are initialized to the
default value of the element type, 0 for integers.
Arrays can store any element type you specify, such as the following example that declares an array of strings:
Array Initialization
You can initialize the elements of an array when you declare the array. The length specifier isn't needed because it's
inferred by the number of elements in the initialization list. For example:
The following code shows a declaration of a string array where each array element is initialized by a name of a
day:
string[] weekDays = new string[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
You can avoid the new expression and the array type when you initialize an array upon declaration, as shown in
the following code. This is called an implicitly typed array:
int[] array2 = { 1, 3, 5, 7, 9 };
string[] weekDays2 = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
You can declare an array variable without creating it, but you must use the new operator when you assign a new
array to this variable. For example:
int[] array3;
array3 = new int[] { 1, 3, 5, 7, 9 }; // OK
//array3 = {1, 3, 5, 7, 9}; // Error
See also
Array
Arrays
Multidimensional Arrays
Jagged Arrays
Multidimensional Arrays (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
Arrays can have more than one dimension. For example, the following declaration creates a two-dimensional
array of four rows and two columns.
Array Initialization
You can initialize the array upon declaration, as is shown in the following example.
// Two-dimensional array.
int[,] array2D = new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };
// The same array with dimensions specified.
int[,] array2Da = new int[4, 2] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };
// A similar array with string elements.
string[,] array2Db = new string[3, 2] { { "one", "two" }, { "three", "four" },
{ "five", "six" } };
// Three-dimensional array.
int[, ,] array3D = new int[,,] { { { 1, 2, 3 }, { 4, 5, 6 } },
{ { 7, 8, 9 }, { 10, 11, 12 } } };
// The same array with dimensions specified.
int[, ,] array3Da = new int[2, 2, 3] { { { 1, 2, 3 }, { 4, 5, 6 } },
{ { 7, 8, 9 }, { 10, 11, 12 } } };
// Output:
// 1
// 2
// 3
// 4
// 7
// three
// 8
// 12
// 12 equals 12
You can also initialize the array without specifying the rank.
int[,] array4 = { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };
If you choose to declare an array variable without initialization, you must use the new operator to assign an array
to the variable. The use of new is shown in the following example.
int[,] array5;
array5 = new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } }; // OK
//array5 = {{1,2}, {3,4}, {5,6}, {7,8}}; // Error
array5[2, 1] = 25;
Similarly, the following example gets the value of a particular array element and assigns it to variable
elementValue .
The following code example initializes the array elements to default values (except for jagged arrays).
See also
C# Programming Guide
Arrays
Single-Dimensional Arrays
Jagged Arrays
Jagged Arrays (C# Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
A jagged array is an array whose elements are arrays. The elements of a jagged array can be of different
dimensions and sizes. A jagged array is sometimes called an "array of arrays." The following examples show how
to declare, initialize, and access jagged arrays.
The following is a declaration of a single-dimensional array that has three elements, each of which is a single-
dimensional array of integers:
Before you can use jaggedArray , its elements must be initialized. You can initialize the elements like this:
Each of the elements is a single-dimensional array of integers. The first element is an array of 5 integers, the
second is an array of 4 integers, and the third is an array of 2 integers.
It is also possible to use initializers to fill the array elements with values, in which case you do not need the array
size. For example:
You can also initialize the array upon declaration like this:
You can use the following shorthand form. Notice that you cannot omit the new operator from the elements
initialization because there is no default initialization for the elements:
int[][] jaggedArray3 =
{
new int[] { 1, 3, 5, 7, 9 },
new int[] { 0, 2, 4, 6 },
new int[] { 11, 22 }
};
A jagged array is an array of arrays, and therefore its elements are reference types and are initialized to null .
You can access individual array elements like these examples:
// Assign 77 to the second element ([1]) of the first array ([0]):
jaggedArray3[0][1] = 77;
It is possible to mix jagged and multidimensional arrays. The following is a declaration and initialization of a
single-dimensional jagged array that contains three two-dimensional array elements of different sizes. For more
information about two-dimensional arrays, see Multidimensional Arrays.
You can access individual elements as shown in this example, which displays the value of the element [1,0] of
the first array (value 5 ):
The method Length returns the number of arrays contained in the jagged array. For example, assuming you have
declared the previous array, this line:
System.Console.WriteLine(jaggedArray4.Length);
returns a value of 3.
Example
This example builds an array whose elements are themselves arrays. Each one of the array elements has a
different size.
class ArrayTest
{
static void Main()
{
// Declare the array of two elements.
int[][] arr = new int[2][];
See also
Array
C# Programming Guide
Arrays
Single-Dimensional Arrays
Multidimensional Arrays
Using foreach with arrays (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
The foreach statement provides a simple, clean way to iterate through the elements of an array.
For single-dimensional arrays, the foreach statement processes elements in increasing index order, starting with
index 0 and ending with index Length - 1 :
For multi-dimensional arrays, elements are traversed such that the indices of the rightmost dimension are
increased first, then the next left dimension, and so on to the left:
However, with multidimensional arrays, using a nested for loop gives you more control over the order in which to
process the array elements.
See also
Array
C# Programming Guide
Arrays
Single-Dimensional Arrays
Multidimensional Arrays
Jagged Arrays
Passing arrays as arguments (C# Programming
Guide)
9/3/2020 • 3 minutes to read • Edit Online
Arrays can be passed as arguments to method parameters. Because arrays are reference types, the method can
change the value of the elements.
int[] theArray = { 1, 3, 5, 7, 9 };
PrintArray(theArray);
You can initialize and pass a new array in one step, as is shown in the following example.
Example
In the following example, an array of strings is initialized and passed as an argument to a DisplayArray method for
strings. The method displays the elements of the array. Next, the ChangeArray method reverses the array elements,
and then the ChangeArrayElements method modifies the first three elements of the array. After each method
returns, the DisplayArray method shows that passing an array by value doesn't prevent changes to the array
elements.
using System;
class ArrayExample
{
static void DisplayArray(string[] arr) => Console.WriteLine(string.Join(" ", arr));
int[,] theArray = { { 1, 2 }, { 2, 3 }, { 3, 4 } };
Print2DArray(theArray);
The following code shows a partial declaration of a print method that accepts a two-dimensional array as its
argument.
void Print2DArray(int[,] arr)
{
// Method code.
}
You can initialize and pass a new array in one step, as is shown in the following example:
Example
In the following example, a two-dimensional array of integers is initialized and passed to the Print2DArray
method. The method displays the elements of the array.
class ArrayClass2D
{
static void Print2DArray(int[,] arr)
{
// Display the array elements.
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
System.Console.WriteLine("Element({0},{1})={2}", i, j, arr[i, j]);
}
}
}
static void Main()
{
// Pass the array as an argument.
Print2DArray(new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } });
See also
C# Programming Guide
Arrays
Single-Dimensional Arrays
Multidimensional Arrays
Jagged Arrays
Implicitly Typed Arrays (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
You can create an implicitly-typed array in which the type of the array instance is inferred from the elements
specified in the array initializer. The rules for any implicitly-typed variable also apply to implicitly-typed arrays. For
more information, see Implicitly Typed Local Variables.
Implicitly-typed arrays are usually used in query expressions together with anonymous types and object and
collection initializers.
The following examples show how to create an implicitly-typed array:
class ImplicitlyTypedArraySample
{
static void Main()
{
var a = new[] { 1, 10, 100, 1000 }; // int[]
var b = new[] { "hello", null, "world" }; // string[]
In the previous example, notice that with implicitly-typed arrays, no square brackets are used on the left side of the
initialization statement. Note also that jagged arrays are initialized by using new [] just like single-dimension
arrays.
See also
C# Programming Guide
Implicitly Typed Local Variables
Arrays
Anonymous Types
Object and Collection Initializers
var
LINQ in C#
Strings (C# Programming Guide)
9/3/2020 • 12 minutes to read • Edit Online
A string is an object of type String whose value is text. Internally, the text is stored as a sequential read-only
collection of Char objects. There is no null-terminating character at the end of a C# string; therefore a C# string
can contain any number of embedded null characters ('\0'). The Length property of a string represents the
number of Char objects it contains, not the number of Unicode characters. To access the individual Unicode code
points in a string, use the StringInfo object.
// Initialize to null.
string message2 = null;
Note that you do not use the new operator to create a string object except when initializing the string with an
array of chars.
Initialize a string with the Empty constant value to create a new String object whose string is of zero length. The
string literal representation of a zero-length string is "". By initializing strings with the Empty value instead of null,
you can reduce the chances of a NullReferenceException occurring. Use the static IsNullOrEmpty(String) method
to verify the value of a string before you try to access it.
System.Console.WriteLine(s1);
// Output: A string is more than the sum of its chars.
Because a string "modification" is actually a new string creation, you must use caution when you create
references to strings. If you create a reference to a string, and then "modify" the original string, the reference will
continue to point to the original object instead of the new object that was created when the string was modified.
The following code illustrates this behavior:
System.Console.WriteLine(s2);
//Output: Hello
For more information about how to create new strings that are based on modifications such as search and
replace operations on the original string, see How to modify string contents.
Use verbatim strings for convenience and better readability when the string text contains backslash characters,
for example in file paths. Because verbatim strings preserve new line characters as part of the string text, they can
be used to initialize multiline strings. Use double quotation marks to embed a quotation mark inside a verbatim
string. The following example shows some common uses for verbatim strings:
\\ Backslash 0x005C
\0 Null 0x0000
\a Alert 0x0007
\b Backspace 0x0008
WARNING
When using the \x escape sequence and specifying less than 4 hex digits, if the characters that immediately follow the
escape sequence are valid hex digits (i.e. 0-9, A-F, and a-f), they will be interpreted as being part of the escape sequence.
For example, \xA1 produces "¡", which is code point U+00A1. However, if the next character is "A" or "a", then the escape
sequence will instead be interpreted as being \xA1A and produce " ", which is code point U+0A1A. In such cases,
specifying all 4 hex digits (e.g. \x00A1 ) will prevent any possible misinterpretation.
NOTE
At compile time, verbatim strings are converted to ordinary strings with all the same escape sequences. Therefore, if you
view a verbatim string in the debugger watch window, you will see the escape characters that were added by the compiler,
not the verbatim version from your source code. For example, the verbatim string @"C:\files.txt" will appear in the
watch window as "C:\\files.txt".
Format Strings
A format string is a string whose contents are determined dynamically at runtime. Format strings are created by
embedding interpolated expressions or placeholders inside of braces within a string. Everything inside the braces
( {...} ) will be resolved to a value and output as a formatted string at runtime. There are two methods to create
format strings: string interpolation and composite formatting.
String Interpolation
Available in C# 6.0 and later, interpolated strings are identified by the $ special character and include
interpolated expressions in braces. If you are new to string interpolation, see the String interpolation - C#
interactive tutorial for a quick overview.
Use string interpolation to improve the readability and maintainability of your code. String interpolation achieves
the same results as the String.Format method, but improves ease of use and inline clarity.
// Output:
// Jupiter Hammon was an African American poet born in 1711.
// He was first published in 1761 at the age of 50.
// He'd be over 300 years old today.
Composite Formatting
The String.Format utilizes placeholders in braces to create a format string. This example results in similar output
to the string interpolation method used above.
// Output:
// Phillis Wheatley was an African American poet born in 1753.
// She was first published in 1773 at the age of 20.
// She'd be over 300 years old today.
For more information on formatting .NET types see Formatting Types in .NET.
Substrings
A substring is any sequence of characters that is contained in a string. Use the Substring method to create a new
string from a part of the original string. You can search for one or more occurrences of a substring by using the
IndexOf method. Use the Replace method to replace all occurrences of a specified substring with a new string.
Like the Substring method, Replace actually returns a new string and does not modify the original string. For
more information, see How to search strings and How to modify string contents.
System.Console.WriteLine(s3.Replace("C#", "Basic"));
// Output: "Visual Basic Express"
If the String methods do not provide the functionality that you must have to modify individual characters in a
string, you can use a StringBuilder object to modify the individual chars "in-place", and then create a new string to
store the results by using the StringBuilder methods. In the following example, assume that you must modify the
original string in a particular way and then store the results for future use:
string question = "hOW DOES mICROSOFT wORD DEAL WITH THE cAPS lOCK KEY?";
System.Text.StringBuilder sb = new System.Text.StringBuilder(question);
string s = String.Empty;
By contrast, a null string does not refer to an instance of a System.String object and any attempt to call a method
on a null string causes a NullReferenceException. However, you can use null strings in concatenation and
comparison operations with other strings. The following examples illustrate some cases in which a reference to a
null string does and does not cause an exception to be thrown:
static void Main()
{
string str = "hello";
string nullStr = null;
string emptyStr = String.Empty;
// The null character can be displayed and counted, like other chars.
string s1 = "\x0" + "abc";
string s2 = "abc" + "\x0";
// Output of the following line: * abc*
Console.WriteLine("*" + s1 + "*");
// Output of the following line: *abc *
Console.WriteLine("*" + s2 + "*");
// Output of the following line: 4
Console.WriteLine(s2.Length);
}
In this example, a StringBuilder object is used to create a string from a set of numeric types:
using System;
using System.Text;
namespace CSRefStrings
{
class TestStringBuilder
{
static void Main()
{
var sb = new StringBuilder();
Related Topics
TO P IC DESC RIP T IO N
How to modify string contents Illustrates techniques to transform strings and modify the
contents of strings.
How to compare strings Shows how to perform ordinal and culture specific
comparisons of strings.
How to concatenate multiple strings Demonstrates various ways to join multiple strings into one.
How to parse strings using String.Split Contains code examples that illustrate how to use the
String.Split method to parse strings.
How to search strings Explains how to use search for specific text or patterns in
strings.
How to determine whether a string represents a numeric Shows how to safely parse a string to see whether it has a
value valid numeric value.
Basic String Operations Provides links to topics that use System.String and
System.Text.StringBuilder methods to perform basic string
operations.
Parsing Date and Time Strings in .NET Shows how to convert a string such as "01/24/2008" to a
System.DateTime object.
Using the StringBuilder Class Describes how to create and modify dynamic string objects
by using the StringBuilder class.
LINQ and Strings Provides information about how to perform various string
operations by using LINQ queries.
To determine whether a string is a valid representation of a specified numeric type, use the static TryParse
method that is implemented by all primitive numeric types and also by types such as DateTime and IPAddress. The
following example shows how to determine whether "108" is a valid int.
int i = 0;
string s = "108";
bool result = int.TryParse(s, out i); //i now = 108
If the string contains nonnumeric characters or the numeric value is too large or too small for the particular type
you have specified, TryParse returns false and sets the out parameter to zero. Otherwise, it returns true and sets
the out parameter to the numeric value of the string.
NOTE
A string may contain only numeric characters and still not be valid for the type whose TryParse method that you use. For
example, "256" is not a valid value for byte but it is valid for int . "98.6" is not a valid value for int but it is a valid
decimal .
Example
The following examples show how to use TryParse with string representations of long , byte , and decimal
values.
byte number2 = 0;
numString = "255"; // A value of 256 will return false
canConvert = byte.TryParse(numString, out number2);
if (canConvert == true)
Console.WriteLine("number2 now = {0}", number2);
else
Console.WriteLine("numString is not a valid byte");
decimal number3 = 0;
numString = "27.3"; //"27" is also a valid decimal
canConvert = decimal.TryParse(numString, out number3);
if (canConvert == true)
Console.WriteLine("number3 now = {0}", number3);
else
Console.WriteLine("number3 is not a valid decimal");
Robust Programming
Primitive numeric types also implement the Parse static method, which throws an exception if the string is not a
valid number. TryParse is generally more efficient because it just returns false if the number is not valid.
.NET Security
Always use the TryParse or Parse methods to validate user input from controls such as text boxes and combo
boxes.
See also
How to convert a byte array to an int
How to convert a string to a number
How to convert between hexadecimal strings and numeric types
Parsing Numeric Strings
Formatting Types
Indexers (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
Indexers allow instances of a class or struct to be indexed just like arrays. The indexed value can be set or
retrieved without explicitly specifying a type or instance member. Indexers resemble properties except that
their accessors take parameters.
The following example defines a generic class with simple get and set accessor methods to assign and retrieve
values. The Program class creates an instance of this class for storing strings.
using System;
class SampleCollection<T>
{
// Declare an array to store the data elements.
private T[] arr = new T[100];
class Program
{
static void Main()
{
var stringCollection = new SampleCollection<string>();
stringCollection[0] = "Hello, World";
Console.WriteLine(stringCollection[0]);
}
}
// The example displays the following output:
// Hello, World.
NOTE
For more examples, see Related Sections.
class SampleCollection<T>
{
// Declare an array to store the data elements.
private T[] arr = new T[100];
int nextIndex = 0;
class Program
{
static void Main()
{
var stringCollection = new SampleCollection<string>();
stringCollection.Add("Hello, World");
System.Console.WriteLine(stringCollection[0]);
}
}
// The example displays the following output:
// Hello, World.
Note that => introduces the expression body, and that the get keyword is not used.
Starting with C# 7.0, both the get and set accessor can be an implemented as expression-bodied members. In
this case, both get and set keywords must be used. For example:
using System;
class SampleCollection<T>
{
// Declare an array to store the data elements.
private T[] arr = new T[100];
class Program
{
static void Main()
{
var stringCollection = new SampleCollection<string>();
stringCollection[0] = "Hello, World.";
Console.WriteLine(stringCollection[0]);
}
}
// The example displays the following output:
// Hello, World.
Indexers Overview
Indexers enable objects to be indexed in a similar manner to arrays.
A get accessor returns a value. A set accessor assigns a value.
The this keyword is used to define the indexer.
The value keyword is used to define the value being assigned by the set indexer.
Indexers do not have to be indexed by an integer value; it is up to you how to define the specific look-
up mechanism.
Indexers can be overloaded.
Indexers can have more than one formal parameter, for example, when accessing a two-dimensional
array.
Related Sections
Using Indexers
Indexers in Interfaces
Comparison Between Properties and Indexers
Restricting Accessor Accessibility
C# Language Specification
For more information, see Indexers in the C# Language Specification. The language specification is the
definitive source for C# syntax and usage.
See also
C# Programming Guide
Properties
Using indexers (C# Programming Guide)
9/3/2020 • 6 minutes to read • Edit Online
Indexers are a syntactic convenience that enable you to create a class, struct, or interface that client applications
can access as an array. The compiler will generate an Item property (or an alternatively named property if
IndexerNameAttribute is present), and the appropriate accessor methods. Indexers are most frequently
implemented in types whose primary purpose is to encapsulate an internal collection or array. For example,
suppose you have a class TempRecord that represents the temperature in Fahrenheit as recorded at 10 different
times during a 24-hour period. The class contains a temps array of type float[] to store the temperature values.
By implementing an indexer in this class, clients can access the temperatures in a TempRecord instance as
float temp = tempRecord[4] instead of as float temp = tempRecord.temps[4] . The indexer notation not only
simplifies the syntax for client applications; it also makes the class, and its purpose more intuitive for other
developers to understand.
To declare an indexer on a class or struct, use the this keyword, as the following example shows:
// Indexer declaration
public int this[int index]
{
// get and set accessors
}
IMPORTANT
Declaring an indexer will automatically generate a property named Item on the object. The Item property is not directly
accessible from the instance member access expression. Additionally, if you add your own Item property to an object with
an indexer, you'll get a CS0102 compiler error. To avoid this error, use the IndexerNameAttribute rename the indexer as
detailed below.
Remarks
The type of an indexer and the type of its parameters must be at least as accessible as the indexer itself. For more
information about accessibility levels, see Access Modifiers.
For more information about how to use indexers with an interface, see Interface Indexers.
The signature of an indexer consists of the number and types of its formal parameters. It doesn't include the
indexer type or the names of the formal parameters. If you declare more than one indexer in the same class, they
must have different signatures.
An indexer value is not classified as a variable; therefore, you cannot pass an indexer value as a ref or out
parameter.
To provide the indexer with a name that other languages can use, use
System.Runtime.CompilerServices.IndexerNameAttribute, as the following example shows:
// Indexer declaration
[System.Runtime.CompilerServices.IndexerName("TheItem")]
public int this[int index]
{
// get and set accessors
}
This indexer will have the name TheItem , as it is overridden by the indexer name attribute. By default, the indexer
name is Item .
Example 1
The following example shows how to declare a private array field, temps , and an indexer. The indexer enables
direct access to the instance tempRecord[i] . The alternative to using the indexer is to declare the array as a public
member and access its members, tempRecord.temps[i] , directly.
// Indexer declaration.
// If index is out of range, the temps array will throw the exception.
public float this[int index]
{
get => temps[index];
set => temps[index] = value;
}
}
Notice that when an indexer's access is evaluated, for example, in a Console.Write statement, the get accessor is
invoked. Therefore, if no get accessor exists, a compile-time error occurs.
using System;
class Program
{
static void Main()
{
var tempRecord = new TempRecord();
Example 2
The following example declares a class that stores the days of the week. A get accessor takes a string, the name
of a day, and returns the corresponding integer. For example, "Sunday" returns 0, "Monday" returns 1, and so on.
using System;
Consuming example 2
using System;
class Program
{
static void Main(string[] args)
{
var week = new DayCollection();
Console.WriteLine(week["Fri"]);
try
{
Console.WriteLine(week["Made-up day"]);
}
catch (ArgumentOutOfRangeException e)
{
Console.WriteLine($"Not supported input: {e.Message}");
}
}
// Output:
// 5
// Not supported input: Day Made-up day is not supported.
// Day input must be in the form "Sun", "Mon", etc (Parameter 'day')
}
Example 3
The following example declares a class that stores the days of the week using the System.DayOfWeek enum. A
get accessor takes a DayOfWeek , the value of a day, and returns the corresponding integer. For example,
DayOfWeek.Sunday returns 0, DayOfWeek.Monday returns 1, and so on.
using System;
using Day = System.DayOfWeek;
class DayOfWeekCollection
{
Day[] days =
{
Day.Sunday, Day.Monday, Day.Tuesday, Day.Wednesday,
Day.Thursday, Day.Friday, Day.Saturday
};
Consuming example 3
using System;
class Program
{
static void Main()
{
var week = new DayOfWeekCollection();
Console.WriteLine(week[DayOfWeek.Friday]);
try
{
Console.WriteLine(week[(DayOfWeek)43]);
}
catch (ArgumentOutOfRangeException e)
{
Console.WriteLine($"Not supported input: {e.Message}");
}
}
// Output:
// 5
// Not supported input: Day 43 is not supported.
// Day input must be a defined System.DayOfWeek value. (Parameter 'day')
}
Robust programming
There are two main ways in which the security and reliability of indexers can be improved:
Be sure to incorporate some type of error-handling strategy to handle the chance of client code passing in
an invalid index value. In the first example earlier in this topic, the TempRecord class provides a Length
property that enables the client code to verify the input before passing it to the indexer. You can also put the
error handling code inside the indexer itself. Be sure to document for users any exceptions that you throw
inside an indexer accessor.
Set the accessibility of the get and set accessors to be as restrictive as is reasonable. This is important for
the set accessor in particular. For more information, see Restricting Accessor Accessibility.
See also
C# Programming Guide
Indexers
Properties
Indexers in Interfaces (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
Indexers can be declared on an interface. Accessors of interface indexers differ from the accessors of class indexers
in the following ways:
Interface accessors do not use modifiers.
An interface accessor typically does not have a body.
The purpose of the accessor is to indicate whether the indexer is read-write, read-only, or write-only. You may
provide an implementation for an indexer defined in an interface, but this is rare. Indexers typically define an API
to access data fields, and data fields cannot be defined in an interface.
The following is an example of an interface indexer accessor:
// Indexer declaration:
string this[int index]
{
get;
set;
}
}
The signature of an indexer must differ from the signatures of all other indexers declared in the same interface.
Example
The following example shows how to implement interface indexers.
// Indexer on an interface:
public interface IIndexInterface
{
// Indexer declaration:
int this[int index]
{
get;
set;
}
}
/* Sample output:
Element #0 = 360877544
Element #1 = 327058047
Element #2 = 1913480832
Element #3 = 1519039937
Element #4 = 601472233
Element #5 = 323352310
Element #6 = 1422639981
Element #7 = 1797892494
Element #8 = 875761049
Element #9 = 393083859
*/
In the preceding example, you could use the explicit interface member implementation by using the fully qualified
name of the interface member. For example
However, the fully qualified name is only needed to avoid ambiguity when the class is implementing more than
one interface with the same indexer signature. For example, if an Employee class is implementing two interfaces,
ICitizen and IEmployee , and both interfaces have the same indexer signature, the explicit interface member
implementation is necessary. That is, the following indexer declaration:
implements the indexer on the IEmployee interface, while the following declaration:
See also
C# Programming Guide
Indexers
Properties
Interfaces
Comparison Between Properties and Indexers (C#
Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
Indexers are like properties. Except for the differences shown in the following table, all the rules that are defined
for property accessors apply to indexer accessors also.
P RO P ERT Y IN DEXER
Allows methods to be called as if they were public data Allows elements of an internal collection of an object to be
members. accessed by using array notation on the object itself.
A get accessor of a property has no parameters. A get accessor of an indexer has the same formal parameter
list as the indexer.
A set accessor of a property contains the implicit value A set accessor of an indexer has the same formal parameter
parameter. list as the indexer, and also to the value parameter.
Supports shortened syntax with Auto-Implemented Supports expression bodied members for get only indexers.
Properties.
See also
C# Programming Guide
Indexers
Properties
Events (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
Events enable a class or object to notify other classes or objects when something of interest occurs. The class
that sends (or raises) the event is called the publisher and the classes that receive (or handle) the event are
called subscribers.
In a typical C# Windows Forms or Web application, you subscribe to events raised by controls such as buttons
and list boxes. You can use the Visual C# integrated development environment (IDE) to browse the events that
a control publishes and select the ones that you want to handle. The IDE provides an easy way to
automatically add an empty event handler method and the code to subscribe to the event. For more
information, see How to subscribe to and unsubscribe from events.
Events Overview
Events have the following properties:
The publisher determines when an event is raised; the subscribers determine what action is taken in
response to the event.
An event can have multiple subscribers. A subscriber can handle multiple events from multiple
publishers.
Events that have no subscribers are never raised.
Events are typically used to signal user actions such as button clicks or menu selections in graphical
user interfaces.
When an event has multiple subscribers, the event handlers are invoked synchronously when an event
is raised. To invoke events asynchronously, see Calling Synchronous Methods Asynchronously.
In the .NET Framework class library, events are based on the EventHandler delegate and the EventArgs
base class.
Related Sections
For more information, see:
How to subscribe to and unsubscribe from events
How to publish events that conform to .NET Guidelines
How to raise base class events in derived classes
How to implement interface events
How to implement custom event accessors
C# Language Specification
For more information, see Events in the C# Language Specification. The language specification is the definitive
source for C# syntax and usage.
See also
EventHandler
C# Programming Guide
Delegates
Creating Event Handlers in Windows Forms
How to subscribe to and unsubscribe from events
(C# Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
You subscribe to an event that is published by another class when you want to write custom code that is called
when that event is raised. For example, you might subscribe to a button's click event in order to make your
application do something useful when the user clicks the button.
To subscribe to events by using the Visual Studio IDE
1. If you cannot see the Proper ties window, in Design view, right-click the form or control for which you
want to create an event handler, and select Proper ties .
2. On top of the Proper ties window, click the Events icon.
3. Double-click the event that you want to create, for example the Load event.
Visual C# creates an empty event handler method and adds it to your code. Alternatively you can add the
code manually in Code view. For example, the following lines of code declare an event handler method that
will be called when the Form class raises the Load event.
The line of code that is required to subscribe to the event is also automatically generated in the
InitializeComponent method in the Form1.Designer.cs file in your project. It resembles this:
2. Use the addition assignment operator ( += ) to attach an event handler to the event. In the following
example, assume that an object named publisher has an event named RaiseCustomEvent . Note that the
subscriber class needs a reference to the publisher class in order to subscribe to its events.
publisher.RaiseCustomEvent += HandleCustomEvent;
Note that the previous syntax is new in C# 2.0. It is exactly equivalent to the C# 1.0 syntax in which the
encapsulating delegate must be explicitly created by using the new keyword:
publisher.RaiseCustomEvent += new CustomEventHandler(HandleCustomEvent);
public Form1()
{
InitializeComponent();
this.Click += (s,e) =>
{
MessageBox.Show(((MouseEventArgs)e).Location.ToString());
};
}
It is important to notice that you cannot easily unsubscribe from an event if you used an anonymous
function to subscribe to it. To unsubscribe in this scenario, it is necessary to go back to the code where you
subscribe to the event, store the anonymous method in a delegate variable, and then add the delegate to
the event. In general, we recommend that you do not use anonymous functions to subscribe to events if
you will have to unsubscribe from the event at some later point in your code. For more information about
anonymous functions, see Anonymous Functions.
Unsubscribing
To prevent your event handler from being invoked when the event is raised, unsubscribe from the event. In order
to prevent resource leaks, you should unsubscribe from events before you dispose of a subscriber object. Until
you unsubscribe from an event, the multicast delegate that underlies the event in the publishing object has a
reference to the delegate that encapsulates the subscriber's event handler. As long as the publishing object holds
that reference, garbage collection will not delete your subscriber object.
To unsubscribe from an event
Use the subtraction assignment operator ( -= ) to unsubscribe from an event:
publisher.RaiseCustomEvent -= HandleCustomEvent;
When all subscribers have unsubscribed from an event, the event instance in the publisher class is set to
null .
See also
Events
event
How to publish events that conform to .NET Guidelines
- and -= operators
+ and += operators
How to publish events that conform to .NET
Guidelines (C# Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
The following procedure demonstrates how to add events that follow the standard .NET pattern to your classes
and structs. All events in the .NET Framework class library are based on the EventHandler delegate, which is
defined as follows:
NOTE
.NET Framework 2.0 introduces a generic version of this delegate, EventHandler<TEventArgs>. The following examples show
how to use both versions.
Although events in classes that you define can be based on any valid delegate type, even delegates that return a
value, it is generally recommended that you base your events on the .NET pattern by using EventHandler, as
shown in the following example.
The name EventHandler can lead to a bit of confusion as it doesn't actually handle the event. The EventHandler,
and generic EventHandler<TEventArgs> are delegate types. A method or lambda expression whose signature
matches the delegate definition is the event handler and will be invoked when the event is raised.
2. (Skip this step if you are using the generic version of EventHandler<TEventArgs>.) Declare a delegate in
your publishing class. Give it a name that ends with EventHandler . The second parameter specifies your
custom EventArgs type.
3. Declare the event in your publishing class by using one of the following steps.
a. If you have no custom EventArgs class, your Event type will be the non-generic EventHandler
delegate. You do not have to declare the delegate because it is already declared in the System
namespace that is included when you create your C# project. Add the following code to your
publisher class.
b. If you are using the non-generic version of EventHandler and you have a custom class derived from
EventArgs, declare your event inside your publishing class and use your delegate from step 2 as the
type.
c. If you are using the generic version, you do not need a custom delegate. Instead, in your publishing
class, you specify your event type as EventHandler<CustomEventArgs> , substituting the name of your
own class between the angle brackets.
Example
The following example demonstrates the previous steps by using a custom EventArgs class and
EventHandler<TEventArgs> as the event type.
using System;
namespace DotNetEvents
{
// Define a class to hold custom event info
public class CustomEventArgs : EventArgs
{
public CustomEventArgs(string message)
{
Message = message;
}
class Program
{
static void Main()
{
var pub = new Publisher();
var sub1 = new Subscriber("sub1", pub);
var sub2 = new Subscriber("sub2", pub);
See also
Delegate
C# Programming Guide
Events
Delegates
How to raise base class events in derived classes (C#
Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
The following simple example shows the standard way to declare events in a base class so that they can also be
raised from derived classes. This pattern is used extensively in Windows Forms classes in the .NET class libraries.
When you create a class that can be used as a base class for other classes, you should consider the fact that events
are a special type of delegate that can only be invoked from within the class that declared them. Derived classes
cannot directly invoke events that are declared within the base class. Although sometimes you may want an event
that can only be raised by the base class, most of the time, you should enable the derived class to invoke base class
events. To do this, you can create a protected invoking method in the base class that wraps the event. By calling or
overriding this invoking method, derived classes can invoke the event indirectly.
NOTE
Do not declare virtual events in a base class and override them in a derived class. The C# compiler does not handle these
correctly and it is unpredictable whether a subscriber to the derived event will actually be subscribing to the base class event.
Example
namespace BaseClassEvents
{
// Special EventArgs class to hold info about Shapes.
public class ShapeEventArgs : EventArgs
{
public ShapeEventArgs(double area)
{
NewArea = area;
}
// The event. Note that by using the generic EventHandler<T> event type
// we do not need to declare a separate delegate type.
public event EventHandler<ShapeEventArgs> ShapeChanged;
public ShapeContainer()
{
_list = new List<Shape>();
}
class Test
{
static void Main()
{
//Create the event publishers and subscriber
var circle = new Circle(54);
var rectangle = new Rectangle(12, 9);
var container = new ShapeContainer();
See also
C# Programming Guide
Events
Delegates
Access Modifiers
Creating Event Handlers in Windows Forms
How to implement interface events (C#
Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
An interface can declare an event. The following example shows how to implement interface events in a class.
Basically the rules are the same as when you implement any interface method or property.
namespace ImplementInterfaceEvents
{
public interface IDrawingObject
{
event EventHandler ShapeChanged;
}
public class MyEventArgs : EventArgs
{
// class members
}
public class Shape : IDrawingObject
{
public event EventHandler ShapeChanged;
void ChangeShape()
{
// Do something here before the event…
OnShapeChanged(new MyEventArgs(/*arguments*/));
Example
The following example shows how to handle the less-common situation in which your class inherits from two or
more interfaces and each interface has an event with the same name. In this situation, you must provide an
explicit interface implementation for at least one of the events. When you write an explicit interface
implementation for an event, you must also write the add and remove event accessors. Normally these are
provided by the compiler, but in this case the compiler cannot provide them.
By providing your own accessors, you can specify whether the two events are represented by the same event in
your class, or by different events. For example, if the events should be raised at different times according to the
interface specifications, you can associate each event with a separate implementation in your class. In the
following example, subscribers determine which OnDraw event they will receive by casting the shape reference to
either an IShape or an IDrawingObject .
namespace WrapTwoInterfaceEvents
{
using System;
Console.WriteLine("Drawing a shape.");
See also
C# Programming Guide
Events
Delegates
Explicit Interface Implementation
How to raise base class events in derived classes
How to implement custom event accessors (C#
Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
An event is a special kind of multicast delegate that can only be invoked from within the class that it is declared in.
Client code subscribes to the event by providing a reference to a method that should be invoked when the event is
fired. These methods are added to the delegate's invocation list through event accessors, which resemble property
accessors, except that event accessors are named add and remove . In most cases, you do not have to supply
custom event accessors. When no custom event accessors are supplied in your code, the compiler will add them
automatically. However, in some cases you may have to provide custom behavior. One such case is shown in the
topic How to implement interface events.
Example
The following example shows how to implement custom add and remove event accessors. Although you can
substitute any code inside the accessors, we recommend that you lock the event before you add or remove a new
event handler method.
See also
Events
event
Generics (C# Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
Generics introduce the concept of type parameters to .NET, which make it possible to design classes and
methods that defer the specification of one or more types until the class or method is declared and
instantiated by client code. For example, by using a generic type parameter T , you can write a single class
that other client code can use without incurring the cost or risk of runtime casts or boxing operations, as
shown here:
Generic classes and methods combine reusability, type safety, and efficiency in a way that their non-generic
counterparts cannot. Generics are most frequently used with collections and the methods that operate on
them. The System.Collections.Generic namespace contains several generic-based collection classes. The non-
generic collections, such as ArrayList are not recommended and are maintained for compatibility purposes.
For more information, see Generics in .NET.
Of course, you can also create custom generic types and methods to provide your own generalized solutions
and design patterns that are type-safe and efficient. The following code example shows a simple generic
linked-list class for demonstration purposes. (In most cases, you should use the List<T> class provided by
.NET instead of creating your own.) The type parameter T is used in several locations where a concrete type
would ordinarily be used to indicate the type of the item stored in the list. It is used in the following ways:
As the type of a method parameter in the AddHead method.
As the return type of the Data property in the nested Node class.
As the type of the private member data in the nested class.
Note that T is available to the nested Node class. When GenericList<T> is instantiated with a concrete
type, for example as a GenericList<int> , each occurrence of T will be replaced with int .
// type parameter T in angle brackets
public class GenericList<T>
{
// The nested class is also generic on T.
private class Node
{
// T used in non-generic constructor.
public Node(T t)
{
next = null;
data = t;
}
// constructor
public GenericList()
{
head = null;
}
The following code example shows how client code uses the generic GenericList<T> class to create a list of
integers. Simply by changing the type argument, the following code could easily be modified to create lists
of strings or any other custom type:
class TestGenericList
{
static void Main()
{
// int is the type argument
GenericList<int> list = new GenericList<int>();
Generics overview
Use generic types to maximize code reuse, type safety, and performance.
The most common use of generics is to create collection classes.
The .NET class library contains several generic collection classes in the System.Collections.Generic
namespace. These should be used whenever possible instead of classes such as ArrayList in the
System.Collections namespace.
You can create your own generic interfaces, classes, methods, events, and delegates.
Generic classes may be constrained to enable access to methods on particular data types.
Information on the types that are used in a generic data type may be obtained at run-time by using
reflection.
Related sections
Generic Type Parameters
Constraints on Type Parameters
Generic Classes
Generic Interfaces
Generic Methods
Generic Delegates
Differences Between C++ Templates and C# Generics
Generics and Reflection
Generics in the Run Time
C# language specification
For more information, see the C# Language Specification.
See also
System.Collections.Generic
C# Programming Guide
Types
<typeparam>
<typeparamref>
Generics in .NET
Generic type parameters (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
In a generic type or method definition, a type parameter is a placeholder for a specific type that a client specifies
when they create an instance of the generic type. A generic class, such as GenericList<T> listed in Introduction to
Generics, cannot be used as-is because it is not really a type; it is more like a blueprint for a type. To use
GenericList<T> , client code must declare and instantiate a constructed type by specifying a type argument inside
the angle brackets. The type argument for this particular class can be any type recognized by the compiler. Any
number of constructed type instances can be created, each one using a different type argument, as follows:
In each of these instances of GenericList<T> , every occurrence of T in the class is substituted at run time with the
type argument. By means of this substitution, we have created three separate type-safe and efficient objects using
a single class definition. For more information on how this substitution is performed by the CLR, see Generics in
the Run Time.
Consider using T as the type parameter name for types with one single letter type parameter.
Consider indicating constraints placed on a type parameter in the name of parameter. For example, a
parameter constrained to ISession may be called TSession .
The code analysis rule CA1715 can be used to ensure that type parameters are named appropriately.
See also
System.Collections.Generic
C# Programming Guide
Generics
Differences Between C++ Templates and C# Generics
Constraints on type parameters (C# Programming
Guide)
9/3/2020 • 10 minutes to read • Edit Online
Constraints inform the compiler about the capabilities a type argument must have. Without any constraints, the
type argument could be any type. The compiler can only assume the members of System.Object, which is the
ultimate base class for any .NET type. For more information, see Why use constraints. If client code uses a type
that doesn't satisfy a constraint, the compiler issues an error. Constraints are specified by using the where
contextual keyword. The following table lists the seven types of constraints:
C O N ST RA IN T DESC RIP T IO N
where T : struct The type argument must be a non-nullable value type. For
information about nullable value types, see Nullable value
types. Because all value types have an accessible
parameterless constructor, the struct constraint implies the
new() constraint and can't be combined with the new()
constraint. You can't combine the struct constraint with
the unmanaged constraint.
where T : class The type argument must be a reference type. This constraint
applies also to any class, interface, delegate, or array type. In
a nullable context in C# 8.0 or later, T must be a non-
nullable reference type.
where T : class? The type argument must be a reference type, either nullable
or non-nullable. This constraint applies also to any class,
interface, delegate, or array type.
where T : <base class name> The type argument must be or derive from the specified base
class. In a nullable context in C# 8.0 and later, T must be a
non-nullable reference type derived from the specified base
class.
C O N ST RA IN T DESC RIP T IO N
where T : <base class name>? The type argument must be or derive from the specified base
class. In a nullable context in C# 8.0 and later, T may be
either a nullable or non-nullable type derived from the
specified base class.
where T : <interface name> The type argument must be or implement the specified
interface. Multiple interface constraints can be specified. The
constraining interface can also be generic. In a nullable
context in C# 8.0 and later, T must be a non-nullable type
that implements the specified interface.
where T : <interface name>? The type argument must be or implement the specified
interface. Multiple interface constraints can be specified. The
constraining interface can also be generic. In a nullable
context in C# 8.0, T may be a nullable reference type, a
non-nullable reference type, or a value type. T may not be a
nullable value type.
public T FindFirstOccurrence(string s)
{
Node current = head;
T t = null;
The constraint enables the generic class to use the Employee.Name property. The constraint specifies that all items
of type T are guaranteed to be either an Employee object or an object that inherits from Employee .
Multiple constraints can be applied to the same type parameter, and the constraints themselves can be generic
types, as follows:
class EmployeeList<T> where T : Employee, IEmployee, System.IComparable<T>, new()
{
// ...
}
When applying the where T : class constraint, avoid the == and != operators on the type parameter because
these operators will test for reference identity only, not for value equality. This behavior occurs even if these
operators are overloaded in a type that is used as an argument. The following code illustrates this point; the
output is false even though the String class overloads the == operator.
The compiler only knows that T is a reference type at compile time and must use the default operators that are
valid for all reference types. If you must test for value equality, the recommended way is to also apply the
where T : IEquatable<T> or where T : IComparable<T> constraint and implement the interface in any class that
will be used to construct the generic class.
class Base { }
class Test<T, U>
where U : struct
where T : Base, new()
{ }
In the previous example, T is a type constraint in the context of the Add method, and an unbounded type
parameter in the context of the List class.
Type parameters can also be used as constraints in generic class definitions. The type parameter must be declared
within the angle brackets together with any other type parameters:
The usefulness of type parameters as constraints with generic classes is limited because the compiler can assume
nothing about the type parameter except that it derives from System.Object . Use type parameters as constraints
on generic classes in scenarios in which you want to enforce an inheritance relationship between two type
parameters.
NotNull constraint
Beginning with C# 8.0 in a nullable context, you can use the notnull constraint to specify that the type argument
must be a non-nullable value type or non-nullable reference type. The notnull constraint can only be used in a
nullable enable context. The compiler generates a warning if you add the notnull constraint in a nullable
oblivious context.
Unlike other constraints, when a type argument violates the notnull constraint, the compiler generates a
warning when that code is compiled in a nullable enable context. If the code is compiled in a nullable oblivious
context, the compiler doesn't generate any warnings or errors.
Beginning with C# 8.0 in a nullable context, the class constraint specifies that the type argument must be a non-
nullable reference type. In a nullable context, when a type parameter is a nullable reference type, the compiler
generates a warning.
Unmanaged constraint
Beginning with C# 7.3, you can use the unmanaged constraint to specify that the type parameter must be a non-
nullable unmanaged type. The unmanaged constraint enables you to write reusable routines to work with types
that can be manipulated as blocks of memory, as shown in the following example:
The preceding method must be compiled in an unsafe context because it uses the sizeof operator on a type not
known to be a built-in type. Without the unmanaged constraint, the sizeof operator is unavailable.
The unmanaged constraint implies the struct constraint and can't be combined with it. Because the struct
constraint implies the new() constraint, the unmanaged constraint can't be combined with the new() constraint
as well.
Delegate constraints
Also beginning with C# 7.3, you can use System.Delegate or System.MulticastDelegate as a base class constraint.
The CLR always allowed this constraint, but the C# language disallowed it. The System.Delegate constraint
enables you to write code that works with delegates in a type-safe manner. The following code defines an
extension method that combines two delegates provided they're the same type:
You can use the above method to combine delegates that are the same type:
If you uncomment the last line, it won't compile. Both first and test are delegate types, but they're different
delegate types.
Enum constraints
Beginning in C# 7.3, you can also specify the System.Enum type as a base class constraint. The CLR always
allowed this constraint, but the C# language disallowed it. Generics using System.Enum provide type-safe
programming to cache results from using the static methods in System.Enum . The following sample finds all the
valid values for an enum type, and then builds a dictionary that maps those values to its string representation.
Enum.GetValues and Enum.GetName use reflection, which has performance implications. You can call
EnumNamedValues to build a collection that is cached and reused rather than repeating the calls that require
reflection.
You could use it as shown in the following sample to create an enum and build a dictionary of its values and
names:
enum Rainbow
{
Red,
Orange,
Yellow,
Green,
Blue,
Indigo,
Violet
}
See also
System.Collections.Generic
C# Programming Guide
Introduction to Generics
Generic Classes
new Constraint
Generic Classes (C# Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
Generic classes encapsulate operations that are not specific to a particular data type. The most common use for
generic classes is with collections like linked lists, hash tables, stacks, queues, trees, and so on. Operations such as
adding and removing items from the collection are performed in basically the same way regardless of the type of
data being stored.
For most scenarios that require collection classes, the recommended approach is to use the ones provided in the
.NET class library. For more information about using these classes, see Generic Collections in .NET.
Typically, you create generic classes by starting with an existing concrete class, and changing types into type
parameters one at a time until you reach the optimal balance of generalization and usability. When creating your
own generic classes, important considerations include the following:
Which types to generalize into type parameters.
As a rule, the more types you can parameterize, the more flexible and reusable your code becomes.
However, too much generalization can create code that is difficult for other developers to read or
understand.
What constraints, if any, to apply to the type parameters (See Constraints on Type Parameters).
A good rule is to apply the maximum constraints possible that will still let you handle the types you must
handle. For example, if you know that your generic class is intended for use only with reference types, apply
the class constraint. That will prevent unintended use of your class with value types, and will enable you to
use the as operator on T , and check for null values.
Whether to factor generic behavior into base classes and subclasses.
Because generic classes can serve as base classes, the same design considerations apply here as with non-
generic classes. See the rules about inheriting from generic base classes later in this topic.
Whether to implement one or more generic interfaces.
For example, if you are designing a class that will be used to create items in a generics-based collection, you
may have to implement an interface such as IComparable<T> where T is the type of your class.
For an example of a simple generic class, see Introduction to Generics.
The rules for type parameters and constraints have several implications for generic class behavior, especially
regarding inheritance and member accessibility. Before proceeding, you should understand some terms. For a
generic class Node<T>, client code can reference the class either by specifying a type argument, to create a closed
constructed type ( Node<int> ). Alternatively, it can leave the type parameter unspecified, for example when you
specify a generic base class, to create an open constructed type ( Node<T> ). Generic classes can inherit from
concrete, closed constructed, or open constructed base classes:
class BaseNode { }
class BaseNodeGeneric<T> { }
// concrete type
class NodeConcrete<T> : BaseNode { }
Non-generic, in other words, concrete, classes can inherit from closed constructed base classes, but not from open
constructed classes or from type parameters because there is no way at run time for client code to supply the type
argument required to instantiate the base class.
//No error
class Node1 : BaseNodeGeneric<int> { }
//Generates an error
//class Node2 : BaseNodeGeneric<T> {}
//Generates an error
//class Node3 : T {}
Generic classes that inherit from open constructed types must supply type arguments for any base class type
parameters that are not shared by the inheriting class, as demonstrated in the following code:
//No error
class Node4<T> : BaseNodeMultiple<T, int> { }
//No error
class Node5<T, U> : BaseNodeMultiple<T, U> { }
//Generates an error
//class Node6<T> : BaseNodeMultiple<T, U> {}
Generic classes that inherit from open constructed types must specify constraints that are a superset of, or imply,
the constraints on the base type:
Generic types can use multiple type parameters and constraints, as follows:
Open constructed and closed constructed types can be used as method parameters:
void Swap<T>(List<T> list1, List<T> list2)
{
//code to swap items
}
If a generic class implements an interface, all instances of that class can be cast to that interface.
Generic classes are invariant. In other words, if an input parameter specifies a List<BaseClass> , you will get a
compile-time error if you try to provide a List<DerivedClass> .
See also
System.Collections.Generic
C# Programming Guide
Generics
Saving the State of Enumerators
An Inheritance Puzzle, Part One
Generic Interfaces (C# Programming Guide)
9/3/2020 • 4 minutes to read • Edit Online
It is often useful to define interfaces either for generic collection classes, or for the generic classes that represent
items in the collection. The preference for generic classes is to use generic interfaces, such as IComparable<T>
rather than IComparable, in order to avoid boxing and unboxing operations on value types. The .NET Framework
class library defines several generic interfaces for use with the collection classes in the System.Collections.Generic
namespace.
When an interface is specified as a constraint on a type parameter, only types that implement the interface can be
used. The following code example shows a SortedList<T> class that derives from the GenericList<T> class. For
more information, see Introduction to Generics. SortedList<T> adds the constraint where T : IComparable<T> . This
enables the BubbleSort method in SortedList<T> to use the generic CompareTo method on list elements. In this
example, list elements are a simple class, Person , that implements IComparable<Person> .
do
{
Node previous = null;
Node current = head;
swapped = false;
if (previous == null)
{
head = tmp;
}
else
{
previous.next = tmp;
}
previous = tmp;
swapped = true;
}
else
{
previous = current;
current = current.next;
}
}
} while (swapped);
}
}
// A simple class that implements IComparable<T> using itself as the
// type argument. This is a common design pattern in objects that
// are stored in generic lists.
public class Person : System.IComparable<Person>
{
string name;
int age;
class Program
{
static void Main()
{
//Declare and instantiate a new generic SortedList class.
//Person is the type argument.
SortedList<Person> list = new SortedList<Person>();
int[] ages = new int[] { 45, 19, 28, 23, 18, 9, 108, 72, 30, 35 };
interface IMonth<T> { }
Generic interfaces can inherit from non-generic interfaces if the generic interface is contravariant, which means it
only uses its type parameter as a return value. In the .NET Framework class library, IEnumerable<T> inherits from
IEnumerable because IEnumerable<T> only uses T in the return value of GetEnumerator and in the Current
property getter.
Concrete classes can implement closed constructed interfaces, as follows:
interface IBaseInterface<T> { }
Generic classes can implement generic interfaces or closed constructed interfaces as long as the class parameter
list supplies all arguments required by the interface, as follows:
interface IBaseInterface1<T> { }
interface IBaseInterface2<T, U> { }
The rules that control method overloading are the same for methods within generic classes, generic structs, or
generic interfaces. For more information, see Generic Methods.
See also
C# Programming Guide
Introduction to Generics
interface
Generics
Generic Methods (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
The following code example shows one way to call the method by using int for the type argument:
You can also omit the type argument and the compiler will infer it. The following call to Swap is equivalent to the
previous call:
The same rules for type inference apply to static methods and instance methods. The compiler can infer the type
parameters based on the method arguments you pass in; it cannot infer the type parameters only from a
constraint or return value. Therefore type inference does not work with methods that have no parameters. Type
inference occurs at compile time before the compiler tries to resolve overloaded method signatures. The compiler
applies type inference logic to all generic methods that share the same name. In the overload resolution step, the
compiler includes only those generic methods on which type inference succeeded.
Within a generic class, non-generic methods can access the class-level type parameters, as follows:
class SampleClass<T>
{
void Swap(ref T lhs, ref T rhs) { }
}
If you define a generic method that takes the same type parameters as the containing class, the compiler generates
warning CS0693 because within the method scope, the argument supplied for the inner T hides the argument
supplied for the outer T . If you require the flexibility of calling a generic class method with type arguments other
than the ones provided when the class was instantiated, consider providing another identifier for the type
parameter of the method, as shown in GenericList2<T> in the following example.
class GenericList<T>
{
// CS0693
void SampleMethod<T>() { }
}
class GenericList2<T>
{
//No warning
void SampleMethod<U>() { }
}
Use constraints to enable more specialized operations on type parameters in methods. This version of Swap<T> ,
now named SwapIfGreater<T> , can only be used with type arguments that implement IComparable<T>.
Generic methods can be overloaded on several type parameters. For example, the following methods can all be
located in the same class:
void DoWork() { }
void DoWork<T>() { }
void DoWork<T, U>() { }
C# Language Specification
For more information, see the C# Language Specification.
See also
System.Collections.Generic
C# Programming Guide
Introduction to Generics
Methods
Generics and Arrays (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
In C# 2.0 and later, single-dimensional arrays that have a lower bound of zero automatically implement IList<T>.
This enables you to create generic methods that can use the same code to iterate through arrays and other
collection types. This technique is primarily useful for reading data in collections. The IList<T> interface cannot be
used to add or remove elements from an array. An exception will be thrown if you try to call an IList<T> method
such as RemoveAt on an array in this context.
The following code example demonstrates how a single generic method that takes an IList<T> input parameter can
iterate through both a list and an array, in this case an array of integers.
class Program
{
static void Main()
{
int[] arr = { 0, 1, 2, 3, 4 };
List<int> list = new List<int>();
ProcessItems<int>(arr);
ProcessItems<int>(list);
}
See also
System.Collections.Generic
C# Programming Guide
Generics
Arrays
Generics
Generic Delegates (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
A delegate can define its own type parameters. Code that references the generic delegate can specify the type
argument to create a closed constructed type, just like when instantiating a generic class or calling a generic
method, as shown in the following example:
C# version 2.0 has a new feature called method group conversion, which applies to concrete as well as generic
delegate types, and enables you to write the previous line with this simplified syntax:
Del<int> m2 = Notify;
Delegates defined within a generic class can use the generic class type parameters in the same way that class
methods do.
class Stack<T>
{
T[] items;
int index;
Code that references the delegate must specify the type argument of the containing class, as follows:
Generic delegates are especially useful in defining events based on the typical design pattern because the sender
argument can be strongly typed and no longer has to be cast to and from Object.
delegate void StackEventHandler<T, U>(T sender, U eventArgs);
class Stack<T>
{
public class StackEventArgs : System.EventArgs { }
public event StackEventHandler<Stack<T>, StackEventArgs> stackEvent;
class SampleClass
{
public void HandleStackChange<T>(Stack<T> stack, Stack<T>.StackEventArgs args) { }
}
See also
System.Collections.Generic
C# Programming Guide
Introduction to Generics
Generic Methods
Generic Classes
Generic Interfaces
Delegates
Generics
Differences Between C++ Templates and C# Generics
(C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
C# Generics and C++ templates are both language features that provide support for parameterized types.
However, there are many differences between the two. At the syntax level, C# generics are a simpler approach to
parameterized types without the complexity of C++ templates. In addition, C# does not attempt to provide all of
the functionality that C++ templates provide. At the implementation level, the primary difference is that C#
generic type substitutions are performed at runtime and generic type information is thereby preserved for
instantiated objects. For more information, see Generics in the Run Time.
The following are the key differences between C# Generics and C++ templates:
C# generics do not provide the same amount of flexibility as C++ templates. For example, it is not possible
to call arithmetic operators in a C# generic class, although it is possible to call user defined operators.
C# does not allow non-type template parameters, such as template C<int i> {} .
C# does not support explicit specialization; that is, a custom implementation of a template for a specific
type.
C# does not support partial specialization: a custom implementation for a subset of the type arguments.
C# does not allow the type parameter to be used as the base class for the generic type.
C# does not allow type parameters to have default types.
In C#, a generic type parameter cannot itself be a generic, although constructed types can be used as
generics. C++ does allow template parameters.
C++ allows code that might not be valid for all type parameters in the template, which is then checked for
the specific type used as the type parameter. C# requires code in a class to be written in such a way that it
will work with any type that satisfies the constraints. For example, in C++ it is possible to write a function
that uses the arithmetic operators + and - on objects of the type parameter, which will produce an error
at the time of instantiation of the template with a type that does not support these operators. C# disallows
this; the only language constructs allowed are those that can be deduced from the constraints.
See also
C# Programming Guide
Introduction to Generics
Templates
Generics in the Run Time (C# Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
When a generic type or method is compiled into Microsoft intermediate language (MSIL), it contains metadata
that identifies it as having type parameters. How the MSIL for a generic type is used differs based on whether the
supplied type parameter is a value type or reference type.
When a generic type is first constructed with a value type as a parameter, the runtime creates a specialized generic
type with the supplied parameter or parameters substituted in the appropriate locations in the MSIL. Specialized
generic types are created one time for each unique value type that is used as a parameter.
For example, suppose your program code declared a stack that is constructed of integers:
Stack<int> stack;
At this point, the runtime generates a specialized version of the Stack<T> class that has the integer substituted
appropriately for its parameter. Now, whenever your program code uses a stack of integers, the runtime reuses
the generated specialized Stack<T> class. In the following example, two instances of a stack of integers are
created, and they share a single instance of the Stack<int> code:
However, suppose that another Stack<T> class with a different value type such as a long or a user-defined
structure as its parameter is created at another point in your code. As a result, the runtime generates another
version of the generic type and substitutes a long in the appropriate locations in MSIL. Conversions are no longer
necessary because each specialized generic class natively contains the value type.
Generics work somewhat differently for reference types. The first time a generic type is constructed with any
reference type, the runtime creates a specialized generic type with object references substituted for the
parameters in the MSIL. Then, every time that a constructed type is instantiated with a reference type as its
parameter, regardless of what type it is, the runtime reuses the previously created specialized version of the
generic type. This is possible because all references are the same size.
For example, suppose you had two reference types, a Customer class and an Order class, and also suppose that
you created a stack of Customer types:
class Customer { }
class Order { }
Stack<Customer> customers;
At this point, the runtime generates a specialized version of the Stack<T> class that stores object references that
will be filled in later instead of storing data. Suppose the next line of code creates a stack of another reference
type, which is named Order :
As with the previous use of the Stack<T> class created by using the Order type, another instance of the
specialized Stack<T> class is created. The pointers that are contained therein are set to reference an area of
memory the size of a Customer type. Because the number of reference types can vary wildly from program to
program, the C# implementation of generics greatly reduces the amount of code by reducing to one the number
of specialized classes created by the compiler for generic classes of reference types.
Moreover, when a generic C# class is instantiated by using a value type or reference type parameter, reflection can
query it at runtime and both its actual type and its type parameter can be ascertained.
See also
System.Collections.Generic
C# Programming Guide
Introduction to Generics
Generics
Generics and Reflection (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
Because the Common Language Runtime (CLR) has access to generic type information at run time, you can use
reflection to obtain information about generic types in the same way as for non-generic types. For more
information, see Generics in the Run Time.
In .NET Framework 2.0, several new members were added to the Type class to enable run-time information for
generic types. See the documentation on these classes for more information on how to use these methods and
properties. The System.Reflection.Emit namespace also contains new members that support generics. See How to:
Define a Generic Type with Reflection Emit.
For a list of the invariant conditions for terms used in generic reflection, see the IsGenericType property remarks.
SY ST EM . T Y P E M EM B ER N A M E DESC RIP T IO N
GetGenericTypeDefinition Returns the underlying generic type definition for the current
constructed type.
GenericParameterPosition For a Type object that represents a type parameter, gets the
position of the type parameter in the type parameter list of
the generic type definition or generic method definition that
declared the type parameter.
DeclaringMethod Returns the generic method that defined the current generic
type parameter, or null if the type parameter was not defined
by a generic method.
In addition, members of the MethodInfo class enable run-time information for generic methods. See the
IsGenericMethod property remarks for a list of invariant conditions for terms used to reflect on generic methods.
See also
C# Programming Guide
Generics
Reflection and Generic Types
Generics
Generics and Attributes (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
Attributes can be applied to generic types in the same way as non-generic types. For more information on applying
attributes, see Attributes.
Custom attributes are only permitted to reference open generic types, which are generic types for which no type
arguments are supplied, and closed constructed generic types, which supply arguments for all type parameters.
The following examples use this custom attribute:
[CustomAttribute(info = typeof(GenericClass1<>))]
class ClassA { }
Specify multiple type parameters using the appropriate number of commas. In this example, GenericClass2 has
two type parameters:
[CustomAttribute(info = typeof(GenericClass2<,>))]
class ClassB { }
An attribute that references a generic type parameter will cause a compile-time error:
To obtain information about a generic type or type parameter at run time, you can use the methods of
System.Reflection. For more information, see Generics and Reflection
See also
C# Programming Guide
Generics
Attributes
Namespaces (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
Namespaces are heavily used in C# programming in two ways. First, .NET uses namespaces to organize its many
classes, as follows:
System.Console.WriteLine("Hello World!");
System is a namespace and Console is a class in that namespace. The using keyword can be used so that the
complete name is not required, as in the following example:
using System;
Console.WriteLine("Hello");
Console.WriteLine("World!");
namespace SampleNamespace
{
class SampleClass
{
public void SampleMethod()
{
System.Console.WriteLine(
"SampleMethod inside SampleNamespace");
}
}
}
Namespaces overview
Namespaces have the following properties:
They organize large code projects.
They are delimited by using the . operator.
The using directive obviates the requirement to specify the name of the namespace for every class.
The global namespace is the "root" namespace: global::System will always refer to the .NET System
namespace.
C# language specification
For more information, see the Namespaces section of the C# language specification.
See also
C# Programming Guide
Using Namespaces
How to use the My namespace
Identifier names
using Directive
:: Operator
Using namespaces (C# Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
Namespaces are heavily used within C# programs in two ways. Firstly, the .NET classes use namespaces to
organize its many classes. Secondly, declaring your own namespaces can help control the scope of class and
method names in larger programming projects.
Accessing namespaces
Most C# applications begin with a section of using directives. This section lists the namespaces that the
application will be using frequently, and saves the programmer from specifying a fully qualified name every time
that a method that is contained within is used.
For example, by including the line:
using System;
Console.WriteLine("Hello, World!");
Instead of:
System.Console.WriteLine("Hello, World!");
Namespace aliases
You can also use the using directive to create an alias for a namespace. Use the namespace alias qualifier :: to
access the members of the aliased namespace. The following example shows how to create and use a namespace
alias:
using generics = System.Collections.Generic;
namespace AliasExample
{
class TestClass
{
static void Main()
{
generics::Dictionary<string, int> dict = new generics::Dictionary<string, int>()
{
["A"] = 1,
["B"] = 2,
["C"] = 3
};
class Program
{
static void Main(string[] args)
{
// Displays "SampleMethod inside SampleNamespace."
SampleClass outer = new SampleClass();
outer.SampleMethod();
Using the previous code segment, you can add a new class member, C3 , to the namespace N1.N2 as follows:
namespace N1.N2
{
class C3 // N1.N2.C3
{
}
}
In general, use the namespace alias qualifier :: to reference a namespace alias or global:: to reference the
global namespace and . to qualify types or members.
It is an error to use :: with an alias that references a type instead of a namespace. For example:
class TestClass
{
static void Main()
{
// Error
//Alias::WriteLine("Hi");
// OK
Alias.WriteLine("Hi");
}
}
Remember that the word global is not a predefined alias; therefore, global.X does not have any special
meaning. It acquires a special meaning only when it is used with :: .
Compiler warning CS0440 is generated if you define an alias named global because global:: always references
the global namespace and not an alias. For example, the following line generates the warning:
Using :: with aliases is a good idea and protects against the unexpected introduction of additional types. For
example, consider this example:
namespace Library
{
public class C : Alias::Exception { }
}
This works, but if a type named Alias were to subsequently be introduced, Alias. would bind to that type
instead. Using Alias::Exception ensures that Alias is treated as a namespace alias and not mistaken for a type.
See also
C# Programming Guide
Namespaces
Member access expression
:: operator
extern alias
How to use the My namespace (C# Programming
Guide)
9/3/2020 • 2 minutes to read • Edit Online
The Microsoft.VisualBasic.MyServices namespace ( My in Visual Basic) provides easy and intuitive access to a
number of .NET classes, enabling you to write code that interacts with the computer, application, settings,
resources, and so on. Although originally designed for use with Visual Basic, the MyServices namespace can be
used in C# applications.
For more information about using the MyServices namespace from Visual Basic, see Development with My.
Add a reference
Before you can use the MyServices classes in your solution, you must add a reference to the Visual Basic library.
Add a reference to the Visual Basic library
1. In Solution Explorer , right-click the References node, and select Add Reference .
2. When the References dialog box appears, scroll down the list, and select Microsoft.VisualBasic.dll.
You might also want to include the following line in the using section at the start of your program.
using Microsoft.VisualBasic.Devices;
Example
This example calls various static methods contained in the MyServices namespace. For this code to compile, a
reference to Microsoft.VisualBasic.DLL must be added to the project.
using System;
using Microsoft.VisualBasic.Devices;
class TestMyServices
{
static void Main()
{
// Play a sound with the Audio class:
Audio myAudio = new Audio();
Console.WriteLine("Playing sound...");
myAudio.Play(@"c:\WINDOWS\Media\chimes.wav");
if (myComputer.Network.IsAvailable)
{
Console.WriteLine("Computer is connected to network.");
}
else
{
Console.WriteLine("Computer is not connected to network.");
}
}
}
Not all the classes in the MyServices namespace can be called from a C# application: for example, the
FileSystemProxy class is not compatible. In this particular case, the static methods that are part of FileSystem,
which are also contained in VisualBasic.dll, can be used instead. For example, here is how to use one such method
to duplicate a directory:
// Duplicate a directory
Microsoft.VisualBasic.FileIO.FileSystem.CopyDirectory(
@"C:\original_directory",
@"C:\copy_of_original_directory");
See also
C# Programming Guide
Namespaces
Using Namespaces
Unsafe code and pointers (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
To maintain type safety and security, C# does not support pointer arithmetic, by default. However, by using the
unsafe keyword, you can define an unsafe context in which pointers can be used. For more information about
pointers, see Pointer types.
NOTE
In the common language runtime (CLR), unsafe code is referred to as unverifiable code. Unsafe code in C# is not necessarily
dangerous; it is just code whose safety cannot be verified by the CLR. The CLR will therefore only execute unsafe code if it is
in a fully trusted assembly. If you use unsafe code, it is your responsibility to ensure that your code does not introduce
security risks or pointer errors.
Related sections
For more information, see:
Pointer types
Fixed size buffers
C# language specification
For more information, see the Unsafe code topic of the C# language specification.
See also
C# Programming Guide
unsafe
Fixed Size Buffers (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
In C#, you can use the fixed statement to create a buffer with a fixed size array in a data structure. Fixed size buffers
are useful when you write methods that interop with data sources from other languages or platforms. The fixed
array can take any attributes or modifiers that are allowed for regular struct members. The only restriction is that
the array type must be bool , byte , char , short , int , long , sbyte , ushort , uint , ulong , float , or double .
Remarks
In safe code, a C# struct that contains an array does not contain the array elements. Instead, the struct contains a
reference to the elements. You can embed an array of fixed size in a struct when it is used in an unsafe code block.
Size of the following struct doesn't depend on the number of elements in the array, since pathName is a
reference:
A struct can contain an embedded array in unsafe code. In the following example, the fixedBuffer array has a
fixed size. You use a fixed statement to establish a pointer to the first element. You access the elements of the
array through this pointer. The fixed statement pins the fixedBuffer instance field to a specific location in
memory.
internal unsafe struct Buffer
{
public fixed char fixedBuffer[128];
}
unsafe
{
// Pin the buffer to a fixed location in memory.
fixed (char* charPtr = example.buffer.fixedBuffer)
{
*charPtr = 'A';
}
// Access safely through the index:
char c = example.buffer.fixedBuffer[0];
Console.WriteLine(c);
The size of the 128 element char array is 256 bytes. Fixed size char buffers always take two bytes per character,
regardless of the encoding. This is true even when char buffers are marshaled to API methods or structs with
CharSet = CharSet.Auto or CharSet = CharSet.Ansi . For more information, see CharSet.
The preceding example demonstrates accessing fixed fields without pinning, which is available starting with C#
7.3.
Another common fixed-size array is the bool array. The elements in a bool array are always one byte in size.
bool arrays are not appropriate for creating bit arrays or buffers.
[FixedBuffer(typeof(char), 128)]
public <fixedBuffer>e__FixedBuffer fixedBuffer;
}
Fixed size buffers differ from regular arrays in the following ways:
May only be used in an unsafe context.
May only be instance fields of structs.
They're always vectors, or one-dimensional arrays.
The declaration should include the length, such as fixed char id[8] . You cannot use fixed char id[] .
See also
C# Programming Guide
Unsafe Code and Pointers
fixed Statement
Interoperability
Pointer types (C# Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
In an unsafe context, a type may be a pointer type, a value type, or a reference type. A pointer type declaration
takes one of the following forms:
type* identifier;
void* identifier; //allowed but not recommended
The type specified before the * in a pointer type is called the referent type . Only an unmanaged type can be a
referent type.
Pointer types do not inherit from object and no conversions exist between pointer types and object . Also, boxing
and unboxing do not support pointers. However, you can convert between different pointer types and between
pointer types and integral types.
When you declare multiple pointers in the same declaration, the asterisk (*) is written together with the
underlying type only; it is not used as a prefix to each pointer name. For example:
A pointer cannot point to a reference or to a struct that contains references, because an object reference can be
garbage collected even if a pointer is pointing to it. The garbage collector does not keep track of whether an
object is being pointed to by any pointer types.
The value of the pointer variable of type myType* is the address of a variable of type myType . The following are
examples of pointer type declarations:
The pointer indirection operator * can be used to access the contents at the location pointed to by the pointer
variable. For example, consider the following declaration:
int* myVariable;
The expression *myVariable denotes the int variable found at the address contained in myVariable .
There are several examples of pointers in the topics fixed Statement and Pointer Conversions. The following
example uses the unsafe keyword and the fixed statement, and shows how to increment an interior pointer.
You can paste this code into the Main function of a console application to run it. These examples must be
compiled with the -unsafe compiler option set.
Console.WriteLine("--------");
Console.WriteLine(a[0]);
/*
Output:
10
20
30
--------
10
11
12
--------
12
*/
You cannot apply the indirection operator to a pointer of type void* . However, you can use a cast to convert a
void pointer to any other pointer type, and vice versa.
A pointer can be null . Applying the indirection operator to a null pointer causes an implementation-defined
behavior.
Passing pointers between methods can cause undefined behavior. Consider a method that returns a pointer to a
local variable through an in , out , or ref parameter or as the function result. If the pointer was set in a fixed
block, the variable to which it points may no longer be fixed.
The following table lists the operators and statements that can operate on pointers in an unsafe context:
[] Indexes a pointer.
fixed statement Temporarily fixes a variable so that its address may be found.
For more information about pointer related operators, see Pointer related operators.
C# language specification
For more information, see the Pointer types section of the C# language specification.
See also
C# Programming Guide
Unsafe Code and Pointers
Pointer Conversions
Reference types
Value types
unsafe
Pointer Conversions (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
The following table shows the predefined implicit pointer conversions. Implicit conversions might occur in many
situations, including method invoking and assignment statements.
Explicit pointer conversion is used to perform conversions, for which there is no implicit conversion, by using a cast
expression. The following table shows these conversions.
sbyte, byte, short, ushort, int, uint, long, or ulong Any pointer type
Any pointer type sbyte, byte, short, ushort, int, uint, long, or ulong
Example
In the following example, a pointer to int is converted to a pointer to byte . Notice that the pointer points to the
lowest addressed byte of the variable. When you successively increment the result, up to the size of int (4 bytes),
you can display the remaining bytes of the variable.
unsafe
{
// Convert to byte:
byte* p = (byte*)&number;
See also
C# Programming Guide
Pointer types
Reference types
Value types
unsafe
fixed Statement
stackalloc
How to use pointers to copy an array of bytes (C#
Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
The following example uses pointers to copy bytes from one array to another.
This example uses the unsafe keyword, which enables you to use pointers in the Copy method. The fixed statement
is used to declare pointers to the source and destination arrays. The fixed statement pins the location of the
source and destination arrays in memory so that they will not be moved by garbage collection. The memory blocks
for the arrays are unpinned when the fixed block is completed. Because the Copy method in this example uses
the unsafe keyword, it must be compiled with the -unsafe compiler option.
This example accesses the elements of both arrays using indices rather than a second unmanaged pointer. The
declaration of the pSource and pTarget pointers pins the arrays. This feature is available starting with C# 7.3.
Example
static unsafe void Copy(byte[] source, int sourceOffset, byte[] target,
int targetOffset, int count)
{
// If either array is not instantiated, you cannot complete the copy.
if ((source == null) || (target == null))
{
throw new System.ArgumentException();
}
// If the number of bytes from the offset to the end of the array is
// less than the number of bytes you want to copy, you cannot complete
// the copy.
if ((source.Length - sourceOffset < count) ||
(target.Length - targetOffset < count))
{
throw new System.ArgumentException();
}
// The following fixed statement pins the location of the source and
// target objects in memory so that they will not be moved by garbage
// collection.
fixed (byte* pSource = source, pTarget = target)
{
// Copy the specified number of bytes from source to target.
for (int i = 0; i < count; i++)
{
pTarget[targetOffset + i] = pSource[sourceOffset + i];
}
}
}
See also
C# Programming Guide
Unsafe Code and Pointers
-unsafe (C# Compiler Options)
Garbage Collection
XML documentation comments (C# programming
guide)
9/3/2020 • 2 minutes to read • Edit Online
In C#, you can create documentation for your code by including XML elements in special comment fields
(indicated by triple slashes) in the source code directly before the code block to which the comments refer, for
example.
/// <summary>
/// This class performs an important function.
/// </summary>
public class MyClass {}
When you compile with the -doc option, the compiler will search for all XML tags in the source code and create an
XML documentation file. To create the final documentation based on the compiler-generated file, you can create a
custom tool or use a tool such as DocFX or Sandcastle.
To refer to XML elements (for example, your function processes specific XML elements that you want to describe in
an XML documentation comment), you can use the standard quoting mechanism ( < and > ). To refer to generic
identifiers in code reference ( cref ) elements, you can use either the escape characters (for example,
cref="List<T>" ) or braces ( cref="List{T}" ). As a special case, the compiler parses the braces as angle
brackets to make the documentation comment less cumbersome to author when referring to generic identifiers.
NOTE
The XML documentation comments are not metadata; they are not included in the compiled assembly and therefore they
are not accessible through reflection.
In this section
Recommended tags for documentation comments
Processing the XML file
Delimiters for documentation tags
How to use the XML documentation features
Related sections
For more information, see:
-doc (Process Documentation Comments)
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for C#
syntax and usage.
See also
C# Programming Guide
Recommended tags for documentation comments
(C# programming guide)
9/3/2020 • 2 minutes to read • Edit Online
The C# compiler processes documentation comments in your code and formats them as XML in a file whose
name you specify in the /doc command-line option. To create the final documentation based on the compiler-
generated file, you can create a custom tool, or use a tool such as DocFX or Sandcastle.
Tags are processed on code constructs such as types and type members.
NOTE
Documentation comments cannot be applied to a namespace.
The compiler will process any tag that is valid XML. The following tags provide generally used functionality in
user documentation.
Tags
/// <summary>
/// This property always returns a value < 1.
/// </summary>
See also
C# programming guide
-doc (C# compiler options)
XML documentation comments
Process the XML file (C# programming guide)
9/3/2020 • 5 minutes to read • Edit Online
The compiler generates an ID string for each construct in your code that's tagged to generate documentation. (For
information about how to tag your code, see Recommended Tags for Documentation Comments.) The ID string
uniquely identifies the construct. Programs that process the XML file can use the ID string to identify the
corresponding .NET metadata or reflection item that the documentation applies to.
ID strings
The XML file is not a hierarchical representation of your code. It's a flat list that has a generated ID for each
element.
The compiler observes the following rules when it generates the ID strings:
No white space is in the string.
The first part of the string identifies the kind of member using a single character followed by a colon. The
following member types are used:
C H A RA C T ER M EM B ER T Y P E N OT ES
F field
E event
The second part of the string is the fully qualified name of the item, starting at the root of the namespace.
The name of the item, its enclosing type(s), and namespace are separated by periods. If the name of the item
itself has periods, they are replaced by the hash-sign ('#'). It's assumed that no item has a hash-sign directly
in its name. For example, the fully qualified name of the String constructor is "System.String.#ctor".
For properties and methods, the parameter list enclosed in parentheses follows. If there are no parameters,
no parentheses are present. The parameters are separated by commas. The encoding of each parameter
follows directly how it's encoded in a .NET signature:
Base types. Regular types (ELEMENT_TYPE_CLASS or ELEMENT_TYPE_VALUETYPE) are represented as
the fully qualified name of the type.
Intrinsic types (for example, ELEMENT_TYPE_I4, ELEMENT_TYPE_OBJECT, ELEMENT_TYPE_STRING,
ELEMENT_TYPE_TYPEDBYREF, and ELEMENT_TYPE_VOID) are represented as the fully qualified name
of the corresponding full type. For example, System.Int32 or System.TypedReference.
ELEMENT_TYPE_PTR is represented as a '*' following the modified type.
ELEMENT_TYPE_BYREF is represented as a '@' following the modified type.
ELEMENT_TYPE_PINNED is represented as a '^' following the modified type. The C# compiler never
generates this.
ELEMENT_TYPE_CMOD_REQ is represented as a '|' and the fully qualified name of the modifier class,
following the modified type. The C# compiler never generates this.
ELEMENT_TYPE_CMOD_OPT is represented as a '!' and the fully qualified name of the modifier class,
following the modified type.
ELEMENT_TYPE_SZARRAY is represented as "[]" following the element type of the array.
ELEMENT_TYPE_GENERICARRAY is represented as "[?]" following the element type of the array. The
C# compiler never generates this.
ELEMENT_TYPE_ARRAY is represented as [lowerbound: size ,lowerbound: size ] where the number
of commas is the rank - 1, and the lower bounds and size of each dimension, if known, are
represented in decimal. If a lower bound or size is not specified, it's omitted. If the lower bound and
size for a particular dimension are omitted, the ':' is omitted as well. For example, a 2-dimensional
array with 1 as the lower bounds and unspecified sizes is [1:,1:].
ELEMENT_TYPE_FNPTR is represented as "=FUNC: type (signature)", where type is the return type,
and signature is the arguments of the method. If there are no arguments, the parentheses are
omitted. The C# compiler never generates this.
The following signature components aren't represented because they aren't used to differentiate overloaded
methods:
calling convention
return type
ELEMENT_TYPE_SENTINEL
For conversion operators only ( op_Implicit and op_Explicit ), the return value of the method is encoded
as a '~' followed by the return type.
For generic types, the name of the type is followed by a backtick and then a number that indicates the
number of generic type parameters. For example:
<member name="T:SampleClass`2"> is the tag for a type that is defined as public class SampleClass<T, U> .
For methods that take generic types as parameters, the generic type parameters are specified as numbers
prefaced with backticks (for example `0,`1). Each number represents a zero-based array notation for the
type's generic parameters.
Examples
The following examples show how the ID strings for a class and its members are generated:
namespace N
{
/// <summary>
/// Enter description here for class X.
/// ID string generated is "T:N.X".
/// </summary>
public unsafe class X
{
/// <summary>
/// Enter description here for the first constructor.
/// ID string generated is "M:N.X.#ctor".
/// </summary>
public X() { }
/// <summary>
/// Enter description here for the second constructor.
/// ID string generated is "M:N.X.#ctor(System.Int32)".
/// </summary>
/// <param name="i">Describe parameter.</param>
public X(int i) { }
/// <summary>
/// Enter description here for field q.
/// ID string generated is "F:N.X.q".
/// </summary>
public string q;
/// <summary>
/// Enter description for constant PI.
/// ID string generated is "F:N.X.PI".
/// </summary>
public const double PI = 3.14;
/// <summary>
/// Enter description for method f.
/// ID string generated is "M:N.X.f".
/// </summary>
/// <returns>Describe return value.</returns>
public int f() { return 1; }
/// <summary>
/// Enter description for method bb.
/// ID string generated is "M:N.X.bb(System.String,System.Int32@,System.Void*)".
/// </summary>
/// <param name="s">Describe parameter.</param>
/// <param name="y">Describe parameter.</param>
/// <param name="z">Describe parameter.</param>
/// <returns>Describe return value.</returns>
public int bb(string s, ref int y, void* z) { return 1; }
/// <summary>
/// Enter description for method gg.
/// ID string generated is "M:N.X.gg(System.Int16[],System.Int32[0:,0:])".
/// </summary>
/// <param name="array1">Describe parameter.</param>
/// <param name="array">Describe parameter.</param>
/// <returns>Describe return value.</returns>
public int gg(short[] array1, int[,] array) { return 0; }
/// <summary>
/// Enter description for operator.
/// ID string generated is "M:N.X.op_Addition(N.X,N.X)".
/// </summary>
/// <param name="x">Describe parameter.</param>
/// <param name="xx">Describe parameter.</param>
/// <returns>Describe return value.</returns>
public static X operator +(X x, X xx) { return x; }
/// <summary>
/// <summary>
/// Enter description for property.
/// ID string generated is "P:N.X.prop".
/// </summary>
public int prop { get { return 1; } set { } }
/// <summary>
/// Enter description for event.
/// ID string generated is "E:N.X.d".
/// </summary>
public event D d;
/// <summary>
/// Enter description for property.
/// ID string generated is "P:N.X.Item(System.String)".
/// </summary>
/// <param name="s">Describe parameter.</param>
/// <returns></returns>
public int this[string s] { get { return 1; } }
/// <summary>
/// Enter description for class Nested.
/// ID string generated is "T:N.X.Nested".
/// </summary>
public class Nested { }
/// <summary>
/// Enter description for delegate.
/// ID string generated is "T:N.X.D".
/// </summary>
/// <param name="i">Describe parameter.</param>
public delegate void D(int i);
/// <summary>
/// Enter description for operator.
/// ID string generated is "M:N.X.op_Explicit(N.X)~System.Int32".
/// </summary>
/// <param name="x">Describe parameter.</param>
/// <returns>Describe return value.</returns>
public static explicit operator int(X x) { return 1; }
}
}
See also
C# programming guide
-doc (C# compiler options)
XML documentation comments
Delimiters for documentation tags (C# programming
guide)
9/3/2020 • 2 minutes to read • Edit Online
The use of XML doc comments requires delimiters, which indicate to the compiler where a documentation
comment begins and ends. You can use the following kinds of delimiters with the XML documentation tags:
///
Single-line delimiter. This is the form that is shown in documentation examples and used by the C# project
templates. If there is a white space character following the delimiter, that character is not included in the XML
output.
NOTE
The Visual Studio integrated development environment (IDE) automatically inserts the <summary> and </summary>
tags and moves your cursor within these tags after you type the /// delimiter in the code editor. You can turn this
feature on or off in the Options dialog box.
/** */
Multiline delimiters.
There are some formatting rules to follow when you use the /** */ delimiters:
On the line that contains the /** delimiter, if the remainder of the line is white space, the line is not
processed for comments. If the first character after the /** delimiter is white space, that white space
character is ignored and the rest of the line is processed. Otherwise, the entire text of the line after the
/** delimiter is processed as part of the comment.
On the line that contains the */ delimiter, if there is only white space up to the */ delimiter, that
line is ignored. Otherwise, the text on the line up to the */ delimiter is processed as part of the
comment.
For the lines after the one that begins with the /** delimiter, the compiler looks for a common
pattern at the beginning of each line. The pattern can consist of optional white space and an asterisk (
* ), followed by more optional white space. If the compiler finds a common pattern at the beginning
of each line that does not begin with the /** delimiter or the */ delimiter, it ignores that pattern for
each line.
The following examples illustrate these rules.
The only part of the following comment that's processed is the line that begins with <summary> . The
three tag formats produce the same comments.
/** <summary>text</summary> */
/**
<summary>text</summary>
*/
/**
* <summary>text</summary>
*/
The compiler identifies a common pattern of " * " at the beginning of the second and third lines. The
pattern is not included in the output.
/**
* <summary>
* text </summary>*/
The compiler finds no common pattern in the following comment because the second character on
the third line is not an asterisk. Therefore, all text on the second and third lines is processed as part of
the comment.
/**
* <summary>
text </summary>
*/
The compiler finds no pattern in the following comment for two reasons. First, the number of spaces
before the asterisk is not consistent. Second, the fifth line begins with a tab, which does not match
spaces. Therefore, all text from lines two through five is processed as part of the comment.
/**
* <summary>
* text
* text2
* </summary>
*/
See also
C# programming guide
XML documentation comments
-doc (C# compiler options)
How to use the XML documentation features
9/3/2020 • 4 minutes to read • Edit Online
The following sample provides a basic overview of a type that has been documented.
Example
// If compiling from the command line, compile with: -doc:YourFileName.xml
/// <summary>
/// Class level summary documentation goes here.
/// </summary>
/// <remarks>
/// Longer comments can be associated with a type or member through
/// the remarks tag.
/// </remarks>
public class TestClass : TestInterface
{
/// <summary>
/// Store for the Name property.
/// </summary>
private string _name = null;
/// <summary>
/// The class constructor.
/// </summary>
public TestClass()
{
// TODO: Add Constructor Logic here.
}
/// <summary>
/// Name property.
/// </summary>
/// <value>
/// A value tag is used to describe the property value.
/// </value>
public string Name
{
get
{
if (_name == null)
{
throw new System.Exception("Name is null");
}
return _name;
}
}
/// <summary>
/// Description for SomeMethod.
/// </summary>
/// <param name="s"> Parameter description for s goes here.</param>
/// <seealso cref="System.String">
/// You can use the cref attribute on any tag to reference a type or member
/// and the compiler will check that the reference exists.
/// </seealso>
public void SomeMethod(string s)
{
}
/// <summary>
/// <summary>
/// Some other method.
/// </summary>
/// <returns>
/// Return values are described through the returns tag.
/// </returns>
/// <seealso cref="SomeMethod(string)">
/// Notice the use of the cref attribute to reference a specific method.
/// </seealso>
public int SomeOtherMethod()
{
return 0;
}
/// <summary>
/// The entry point for the application.
/// </summary>
/// <param name="args"> A list of command line arguments.</param>
static int Main(System.String[] args)
{
// TODO: Add code to start application here.
return 0;
}
}
/// <summary>
/// Documentation that describes the interface goes here.
/// </summary>
/// <remarks>
/// Details about the interface go here.
/// </remarks>
interface TestInterface
{
/// <summary>
/// Documentation that describes the method goes here.
/// </summary>
/// <param name="n">
/// Parameter n requires an integer argument.
/// </param>
/// <returns>
/// The method returns an integer.
/// </returns>
int InterfaceMethod(int n);
}
<?xml version="1.0"?>
<doc>
<assembly>
<name>xmlsample</name>
</assembly>
<members>
<member name="T:TestClass">
<summary>
Class level summary documentation goes here.
</summary>
<remarks>
Longer comments can be associated with a type or member through
the remarks tag.
</remarks>
</member>
<member name="F:TestClass._name">
<member name="F:TestClass._name">
<summary>
Store for the Name property.
</summary>
</member>
<member name="M:TestClass.#ctor">
<summary>
The class constructor.
</summary>
</member>
<member name="P:TestClass.Name">
<summary>
Name property.
</summary>
<value>
A value tag is used to describe the property value.
</value>
</member>
<member name="M:TestClass.SomeMethod(System.String)">
<summary>
Description for SomeMethod.
</summary>
<param name="s"> Parameter description for s goes here.</param>
<seealso cref="T:System.String">
You can use the cref attribute on any tag to reference a type or member
and the compiler will check that the reference exists.
</seealso>
</member>
<member name="M:TestClass.SomeOtherMethod">
<summary>
Some other method.
</summary>
<returns>
Return values are described through the returns tag.
</returns>
<seealso cref="M:TestClass.SomeMethod(System.String)">
Notice the use of the cref attribute to reference a specific method.
</seealso>
</member>
<member name="M:TestClass.Main(System.String[])">
<summary>
The entry point for the application.
</summary>
<param name="args"> A list of command line arguments.</param>
</member>
<member name="T:TestInterface">
<summary>
Documentation that describes the interface goes here.
</summary>
<remarks>
Details about the interface go here.
</remarks>
</member>
<member name="M:TestInterface.InterfaceMethod(System.Int32)">
<summary>
Documentation that describes the method goes here.
</summary>
<param name="n">
Parameter n requires an integer argument.
</param>
<returns>
The method returns an integer.
</returns>
</member>
</members>
</doc>
Compiling the code
To compile the example, enter the following command:
csc XMLsample.cs /doc:XMLsample.xml
This command creates the XML file XMLsample.xml, which you can view in your browser or by using the TYPE
command.
Robust programming
XML documentation starts with /// . When you create a new project, the wizards put some starter /// lines in
for you. The processing of these comments has some restrictions:
The documentation must be well-formed XML. If the XML is not well-formed, a warning is generated and
the documentation file will contain a comment that says that an error was encountered.
Developers are free to create their own set of tags. There is a recommended set of tags. Some of the
recommended tags have special meanings:
The <param> tag is used to describe parameters. If used, the compiler verifies that the parameter
exists and that all parameters are described in the documentation. If the verification fails, the
compiler issues a warning.
The cref attribute can be attached to any tag to reference a code element. The compiler verifies that
this code element exists. If the verification fails, the compiler issues a warning. The compiler respects
any using statements when it looks for a type described in the cref attribute.
The <summary> tag is used by IntelliSense inside Visual Studio to display additional information about
a type or member.
NOTE
The XML file does not provide full information about the type and members (for example, it does not contain
any type information). To get full information about a type or member, use the documentation file together
with reflection on the actual type or member.
See also
C# programming guide
-doc (C# compiler options)
XML documentation comments
DocFX documentation processor
Sandcastle documentation processor
<c> (C# programming guide)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
<c>text</c>
Parameters
text
Remarks
The <c> tag gives you a way to indicate that text within a description should be marked as code. Use <code> to
indicate multiple lines as code.
Compile with -doc to process documentation comments to a file.
Example
// compile with: -doc:DocFileName.xml
See also
C# programming guide
Recommended tags for documentation comments
<code> (C# programming guide)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
<code>content</code>
Parameters
content
Remarks
The <code> tag is used to indicate multiple lines of code. Use <c> to indicate that single-line text within a
description should be marked as code.
Compile with -doc to process documentation comments to a file.
Example
See the <example> article for an example of how to use the <code> tag.
See also
C# programming guide
Recommended tags for documentation comments
cref attribute (C# programming guide)
9/3/2020 • 2 minutes to read • Edit Online
The cref attribute in an XML documentation tag means "code reference." It specifies that the inner text of the tag
is a code element, such as a type, method, or property. Documentation tools like DocFX and Sandcastle use the
cref attributes to automatically generate hyperlinks to the page where the type or member is documented.
Example
The following example shows cref attributes used in <see> tags.
namespace TestNamespace
{
/// <summary>
/// TestClass contains several cref examples.
/// </summary>
public class TestClass
{
/// <summary>
/// This sample shows how to specify the <see cref="TestClass"/> constructor as a cref attribute.
/// </summary>
public TestClass()
{ }
/// <summary>
/// This sample shows how to specify the <see cref="TestClass(int)"/> constructor as a cref attribute.
/// </summary>
public TestClass(int value)
{ }
/// <summary>
/// The GetZero method.
/// </summary>
/// <example>
/// This sample shows how to call the <see cref="GetZero"/> method.
/// <code>
/// class TestClass
/// {
/// static int Main()
/// {
/// return GetZero();
/// }
/// }
/// </code>
/// </example>
public static int GetZero()
{
return 0;
}
/// <summary>
/// The GetGenericValue method.
/// </summary>
/// <remarks>
/// This sample shows how to specify the <see cref="GetGenericValue"/> method as a cref attribute.
/// </remarks>
/// <summary>
/// GenericClass.
/// </summary>
/// <remarks>
/// This example shows how to specify the <see cref="GenericClass{T}"/> type as a cref attribute.
/// </remarks>
class GenericClass<T>
{
// Fields and members.
}
class Program
{
static int Main()
{
return TestClass.GetZero();
}
}
}
When compiled, the program produces the following XML file. Notice that the cref attribute for the GetZero
method, for example, has been transformed by the compiler to "M:TestNamespace.TestClass.GetZero" . The "M:"
prefix means "method" and is a convention that is recognized by documentation tools such as DocFX and
Sandcastle. For a complete list of prefixes, see Processing the XML File.
<?xml version="1.0"?>
<doc>
<assembly>
<name>CRefTest</name>
</assembly>
<members>
<member name="T:TestNamespace.TestClass">
<summary>
TestClass contains several cref examples.
</summary>
</member>
<member name="M:TestNamespace.TestClass.#ctor">
<summary>
This sample shows how to specify the <see cref="T:TestNamespace.TestClass"/> constructor as a cref
attribute.
</summary>
</member>
<member name="M:TestNamespace.TestClass.#ctor(System.Int32)">
<summary>
This sample shows how to specify the <see cref="M:TestNamespace.TestClass.#ctor(System.Int32)"/>
constructor as a cref attribute.
</summary>
</member>
<member name="M:TestNamespace.TestClass.GetZero">
<summary>
The GetZero method.
</summary>
<example>
This sample shows how to call the <see cref="M:TestNamespace.TestClass.GetZero"/> method.
<code>
class TestClass
{
static int Main()
{
return GetZero();
}
}
</code>
</example>
</member>
<member name="M:TestNamespace.TestClass.GetGenericValue``1(``0)">
<summary>
The GetGenericValue method.
</summary>
<remarks>
This sample shows how to specify the <see
cref="M:TestNamespace.TestClass.GetGenericValue``1(``0)"/> method as a cref attribute.
</remarks>
</member>
<member name="T:TestNamespace.GenericClass`1">
<summary>
GenericClass.
</summary>
<remarks>
This example shows how to specify the <see cref="T:TestNamespace.GenericClass`1"/> type as a cref
attribute.
</remarks>
</member>
</members>
</doc>
See also
XML documentation comments
Recommended tags for documentation comments
<example> (C# programming guide)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
<example>description</example>
Parameters
description
Remarks
The <example> tag lets you specify an example of how to use a method or other library member. This commonly
involves using the <code> tag.
Compile with -doc to process documentation comments to a file.
Example
// Save this file as CRefTest.cs
// Compile with: csc CRefTest.cs -doc:Results.xml
namespace TestNamespace
{
/// <summary>
/// TestClass contains several cref examples.
/// </summary>
public class TestClass
{
/// <summary>
/// This sample shows how to specify the <see cref="TestClass"/> constructor as a cref attribute.
/// </summary>
public TestClass()
{ }
/// <summary>
/// This sample shows how to specify the <see cref="TestClass(int)"/> constructor as a cref attribute.
/// </summary>
public TestClass(int value)
{ }
/// <summary>
/// The GetZero method.
/// </summary>
/// <example>
/// This sample shows how to call the <see cref="GetZero"/> method.
/// <code>
/// class TestClass
/// {
/// static int Main()
/// {
/// return GetZero();
/// }
/// }
/// }
/// </code>
/// </example>
public static int GetZero()
{
return 0;
}
/// <summary>
/// The GetGenericValue method.
/// </summary>
/// <remarks>
/// This sample shows how to specify the <see cref="GetGenericValue"/> method as a cref attribute.
/// </remarks>
/// <summary>
/// GenericClass.
/// </summary>
/// <remarks>
/// This example shows how to specify the <see cref="GenericClass{T}"/> type as a cref attribute.
/// </remarks>
class GenericClass<T>
{
// Fields and members.
}
class Program
{
static int Main()
{
return TestClass.GetZero();
}
}
}
See also
C# Programming Guide
Recommended tags for documentation comments
<exception> (C# programming guide)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
<exception cref="member">description</exception>
Parameters
cref = " member "
A reference to an exception that is available from the current compilation environment. The compiler checks
that the given exception exists and translates member to the canonical element name in the output XML.
member must appear within double quotation marks (" ").
For more information on how to format member to reference a generic type, see Processing the XML File.
description
Remarks
The <exception> tag lets you specify which exceptions can be thrown. This tag can be applied to definitions for
methods, properties, events, and indexers.
Compile with -doc to process documentation comments to a file.
For more information about exception handling, see Exceptions and Exception Handling.
Example
// compile with: -doc:DocFileName.xml
Syntax
<include file='filename' path='tagpath[@name="id"]' />
Parameters
filename
The name of the XML file containing the documentation. The file name can be qualified with a path relative
to the source code file. Enclose filename in single quotation marks (' ').
tagpath
The path of the tags in filename that leads to the tag name . Enclose the path in single quotation marks (' ').
name
The name specifier in the tag that precedes the comments; name will have an id .
id
The ID for the tag that precedes the comments. Enclose the ID in double quotation marks (" ").
Remarks
The <include> tag lets you refer to comments in another file that describe the types and members in your source
code. This is an alternative to placing documentation comments directly in your source code file. By putting the
documentation in a separate file, you can apply source control to the documentation separately from the source
code. One person can have the source code file checked out and someone else can have the documentation file
checked out.
The <include> tag uses the XML XPath syntax. Refer to XPath documentation for ways to customize your
<include> use.
Example
This is a multifile example. The following is the first file, which uses <include> .
// compile with: -doc:DocFileName.xml
<MyDocs>
<MyMembers name="test">
<summary>
The summary for this type.
</summary>
</MyMembers>
<MyMembers name="test2">
<summary>
The summary for this other type.
</summary>
</MyMembers>
</MyDocs>
Program output
The following output is generated when you compile the Test and Test2 classes with the following command line:
-doc:DocFileName.xml. In Visual Studio, you specify the XML doc comments option in the Build pane of the Project
Designer. When the C# compiler sees the <include> tag, it searches for documentation comments in
xml_include_tag.doc instead of the current source file. The compiler then generates DocFileName.xml, and this is
the file that is consumed by documentation tools such as Sandcastle to produce the final documentation.
<?xml version="1.0"?>
<doc>
<assembly>
<name>xml_include_tag</name>
</assembly>
<members>
<member name="T:Test">
<summary>
The summary for this type.
</summary>
</member>
<member name="T:Test2">
<summary>
The summary for this other type.
</summary>
</member>
</members>
</doc>
See also
C# Programming Guide
Recommended Tags for Documentation Comments
<inheritdoc> (C# Programming Guide)
3/12/2020 • 2 minutes to read • Edit Online
Syntax
<inheritdoc/>
InheritDoc
Inherit XML comments from base classes, interfaces, and similar methods. This eliminates unwanted copying and
pasting of duplicate XML comments and automatically keeps XML comments synchronized.
Remarks
Add your XML comments in base classes or interfaces and let InheritDoc copy the comments to implementing
classes.
Add your XML comments to your synchronous methods and let InheritDoc copy the comments to your
asynchronous versions of the same methods.
If you want to copy the comments from a specific member you can use the cref attribute to specify the member.
Examples
// compile with: -doc:DocFileName.xml
/// <summary>
/// You may have some primary information about this class.
/// </summary>
public class MainClass
{
}
///<inheritdoc/>
public class TestClass: MainClass
{
}
/// <summary>
/// You may have some primary information about this interface.
/// </summary>
public interface ITestInterface
{
}
///<inheritdoc cref="ITestInterface"/>
public class TestClass : ITestInterface
{
}
See also
C# Programming Guide
Recommended Tags for Documentation Comments
<list> (C# programming guide)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
<list type="bullet|number|table">
<listheader>
<term>term</term>
<description>description</description>
</listheader>
<item>
<term>term</term>
<description>description</description>
</item>
</list>
Parameters
term
Remarks
The <listheader> block is used to define the heading row of either a table or definition list. When defining a table,
you only need to supply an entry for term in the heading.
Each item in the list is specified with an <item> block. When creating a definition list, you will need to specify both
term and description . However, for a table, bulleted list, or numbered list, you only need to supply an entry for
description .
Example
// compile with: -doc:DocFileName.xml
See also
C# programming guide
Recommended tags for documentation comments
<para> (C# programming guide)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
<para>content</para>
Parameters
content
Remarks
The <para> tag is for use inside a tag, such as <summary>, <remarks>, or <returns>, and lets you add structure
to the text.
Compile with -doc to process documentation comments to a file.
Example
See <summary> for an example of using <para> .
See also
C# programming guide
Recommended tags for documentation comments
<param> (C# programming guide)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
<param name="name">description</param>
Parameters
name
The name of a method parameter. Enclose the name in double quotation marks (" ").
description
Remarks
The <param> tag should be used in the comment for a method declaration to describe one of the parameters for
the method. To document multiple parameters, use multiple <param> tags.
The text for the <param> tag is displayed in IntelliSense, the Object Browser, and the Code Comment Web Report.
Compile with -doc to process documentation comments to a file.
Example
// compile with: -doc:DocFileName.xml
// Multiple parameters.
/// <param name="Int1">Used to indicate status.</param>
/// <param name="Float1">Used to specify context.</param>
public static void DoWork(int Int1, float Float1)
{
}
See also
C# programming guide
Recommended tags for documentation comments
<paramref> (C# programming guide)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
<paramref name="name"/>
Parameters
name
The name of the parameter to refer to. Enclose the name in double quotation marks (" ").
Remarks
The <paramref>tag gives you a way to indicate that a word in the code comments, for example in a <summary> or
<remarks> block refers to a parameter. The XML file can be processed to format this word in some distinct way,
such as with a bold or italic font.
Compile with -doc to process documentation comments to a file.
Example
// compile with: -doc:DocFileName.xml
See also
C# Programming Guide
Recommended tags for documentation comments
<permission> (C# programming guide)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
<permission cref="member">description</permission>
Parameters
cref = " member "
A reference to a member or field that is available to be called from the current compilation environment. The
compiler checks that the given code element exists and translates member to the canonical element name in
the output XML. member must appear within double quotation marks (" ").
For information on how to create a cref reference to a generic type, see cref attribute.
description
Remarks
The <permission> tag lets you document the access of a member. The PermissionSet class lets you specify access to
a member.
Compile with -doc to process documentation comments to a file.
Example
// compile with: -doc:DocFileName.xml
class TestClass
{
/// <permission cref="System.Security.PermissionSet">Everyone can access this method.</permission>
public static void Test()
{
}
See also
C# programming guide
Recommended tags for documentation comments
<remarks> (C# programming guide)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
<remarks>description</remarks>
Parameters
Description
Remarks
The <remarks> tag is used to add information about a type, supplementing the information specified with
<summary>. This information is displayed in the Object Browser window.
Compile with -doc to process documentation comments to a file.
Example
// compile with: -doc:DocFileName.xml
/// <summary>
/// You may have some primary information about this class.
/// </summary>
/// <remarks>
/// You may have some additional information about this class.
/// </remarks>
public class TestClass
{
/// text for Main
static void Main()
{
}
}
See also
C# Programming Guide
Recommended tags for documentation comments
<returns> (C# programming guide)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
<returns>description</returns>
Parameters
description
Remarks
The <returns> tag should be used in the comment for a method declaration to describe the return value.
Compile with -doc to process documentation comments to a file.
Example
// compile with: -doc:DocFileName.xml
See also
C# programming guide
Recommended tags for documentation comments
<see> (C# programming guide)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
<see cref="member"/>
Parameters
cref = " member "
A reference to a member or field that is available to be called from the current compilation environment.
The compiler checks that the given code element exists and passes member to the element name in the
output XML. Place member within double quotation marks (" ").
Remarks
The <see> tag lets you specify a link from within text. Use <seealso> to indicate that text should be placed in a See
Also section. Use the cref Attribute to create internal hyperlinks to documentation pages for code elements. Also,
href is a valid Attribute that will function as a hyperlink.
See also
C# programming guide
Recommended tags for documentation comments
<seealso> (C# programming guide)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
<seealso cref="member"/>
Parameters
cref = " member "
A reference to a member or field that is available to be called from the current compilation environment.
The compiler checks that the given code element exists and passes member to the element name in the
output XML. member must appear within double quotation marks (" ").
For information on how to create a cref reference to a generic type, see cref attribute.
Remarks
The <seealso> tag lets you specify the text that you might want to appear in a See Also section. Use <see> to
specify a link from within text.
Compile with -doc to process documentation comments to a file.
Example
See <summary> for an example of using <seealso>.
See also
C# programming guide
Recommended tags for documentation comments
<summary> (C# programming guide)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
<summary>description</summary>
Parameters
description
Remarks
The <summary> tag should be used to describe a type or a type member. Use <remarks> to add supplemental
information to a type description. Use the cref Attribute to enable documentation tools such as DocFX and
Sandcastle to create internal hyperlinks to documentation pages for code elements.
The text for the <summary> tag is the only source of information about the type in IntelliSense, and is also
displayed in the Object Browser Window.
Compile with -doc to process documentation comments to a file. To create the final documentation based on the
compiler-generated file, you can create a custom tool, or use a tool such as DocFX or Sandcastle.
Example
// compile with: -doc:DocFileName.xml
Example
The following example shows how to make a cref reference to a generic type.
// the following cref shows how to specify the reference, such that,
// the compiler will resolve the reference
/// <summary cref="C{T}">
/// </summary>
class A { }
class Program
{
static void Main() { }
}
See also
C# programming guide
Recommended tags for documentation comments
<typeparam> (C# programming guide)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
<typeparam name="name">description</typeparam>
Parameters
name
The name of the type parameter. Enclose the name in double quotation marks (" ").
description
Remarks
The <typeparam> tag should be used in the comment for a generic type or method declaration to describe a type
parameter. Add a tag for each type parameter of the generic type or method.
For more information, see Generics.
The text for the <typeparam> tag will be displayed in IntelliSense, the Object Browser Window code comment web
report.
Compile with -doc to process documentation comments to a file.
Example
// compile with: -doc:DocFileName.xml
See also
C# reference
C# programming guide
Recommended tags for documentation comments
<typeparamref> (C# programming guide)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
<typeparamref name="name"/>
Parameters
name
The name of the type parameter. Enclose the name in double quotation marks (" ").
Remarks
For more information on type parameters in generic types and methods, see Generics.
Use this tag to enable consumers of the documentation file to format the word in some distinct way, for example
in italics.
Compile with -doc to process documentation comments to a file.
Example
// compile with: -doc:DocFileName.xml
See also
C# programming guide
Recommended tags for documentation comments
<value> (C# programming guide)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
<value>property-description</value>
Parameters
property-description
Remarks
The <value> tag lets you describe the value that a property represents. When you add a property via code wizard
in the Visual Studio .NET development environment, it adds a <summary> tag for the new property. You should
then manually add a <value> tag to describe the value that the property represents.
Compile with -doc to process documentation comments to a file.
Example
// compile with: -doc:DocFileName.xml
The C# language's exception handling features help you deal with any unexpected or exceptional situations that
occur when a program is running. Exception handling uses the try , catch , and finally keywords to try actions
that may not succeed, to handle failures when you decide that it is reasonable to do so, and to clean up resources
afterward. Exceptions can be generated by the common language runtime (CLR), by .NET or third-party libraries,
or by application code. Exceptions are created by using the throw keyword.
In many cases, an exception may be thrown not by a method that your code has called directly, but by another
method further down in the call stack. When this happens, the CLR will unwind the stack, looking for a method
with a catch block for the specific exception type, and it will execute the first such catch block that if finds. If it
finds no appropriate catch block anywhere in the call stack, it will terminate the process and display a message
to the user.
In this example, a method tests for division by zero and catches the error. Without the exception handling, this
program would terminate with a DivideByZeroException was unhandled error.
class ExceptionTest
{
static double SafeDivision(double x, double y)
{
if (y == 0)
throw new System.DivideByZeroException();
return x / y;
}
static void Main()
{
// Input for test purposes. Change the values to see
// exception handling behavior.
double a = 98, b = 0;
double result = 0;
try
{
result = SafeDivision(a, b);
Console.WriteLine("{0} divided by {1} = {2}", a, b, result);
}
catch (DivideByZeroException e)
{
Console.WriteLine("Attempted divide by zero.");
}
}
}
Exceptions Overview
Exceptions have the following properties:
Exceptions are types that all ultimately derive from System.Exception .
Use a try block around the statements that might throw exceptions.
Once an exception occurs in the try block, the flow of control jumps to the first associated exception handler
that is present anywhere in the call stack. In C#, the catch keyword is used to define an exception handler.
If no exception handler for a given exception is present, the program stops executing with an error message.
Do not catch an exception unless you can handle it and leave the application in a known state. If you catch
System.Exception , re-throw it using the throw keyword at the end of the catch block.
If a catch block defines an exception variable, you can use it to obtain more information about the type of
exception that occurred.
Exceptions can be explicitly generated by a program by using the throw keyword.
Exception objects contain detailed information about the error, such as the state of the call stack and a text
description of the error.
Code in a finally block is executed even if an exception is thrown. Use a finally block to release resources,
for example to close any streams or files that were opened in the try block.
Managed exceptions in .NET are implemented on top of the Win32 structured exception handling mechanism.
For more information, see Structured Exception Handling (C/C++) and A Crash Course on the Depths of
Win32 Structured Exception Handling.
Related Sections
See the following articles for more information about exceptions and exception handling:
Using Exceptions
Exception Handling
Creating and Throwing Exceptions
Compiler-Generated Exceptions
How to handle an exception using try/catch (C# Programming Guide)
How to execute cleanup code using finally
How to catch a non-CLS exception
C# Language Specification
For more information, see Exceptions in the C# Language Specification. The language specification is the
definitive source for C# syntax and usage.
See also
SystemException
C# Programming Guide
C# Keywords
throw
try-catch
try-finally
try-catch-finally
Exceptions
Use exceptions (C# programming guide)
9/3/2020 • 3 minutes to read • Edit Online
In C#, errors in the program at run time are propagated through the program by using a mechanism called
exceptions. Exceptions are thrown by code that encounters an error and caught by code that can correct the error.
Exceptions can be thrown by the .NET runtime or by code in a program. Once an exception is thrown, it propagates
up the call stack until a catch statement for the exception is found. Uncaught exceptions are handled by a generic
exception handler provided by the system that displays a dialog box.
Exceptions are represented by classes derived from Exception. This class identifies the type of exception and
contains properties that have details about the exception. Throwing an exception involves creating an instance of
an exception-derived class, optionally configuring properties of the exception, and then throwing the object by
using the throw keyword. For example:
throw ex;
}
After an exception is thrown, the runtime checks the current statement to see whether it is within a try block. If it
is, any catch blocks associated with the try block are checked to see whether they can catch the exception.
Catch blocks typically specify exception types; if the type of the catch block is the same type as the exception, or
a base class of the exception, the catch block can handle the method. For example:
If the statement that throws an exception is not within a try block or if the try block that encloses it has no
matching catch block, the runtime checks the calling method for a try statement and catch blocks. The runtime
continues up the calling stack, searching for a compatible catch block. After the catch block is found and
executed, control is passed to the next statement after that catch block.
A try statement can contain more than one catch block. The first catch statement that can handle the exception
is executed; any following catch statements, even if they are compatible, are ignored. Therefore, catch blocks
should always be ordered from most specific (or most-derived) to least specific. For example:
using System;
using System.IO;
Console.WriteLine("Done");
}
}
Before the catch block is executed, the runtime checks for finally blocks. Finally blocks enable the
programmer to clean up any ambiguous state that could be left over from an aborted try block, or to release any
external resources (such as graphics handles, database connections or file streams) without waiting for the garbage
collector in the runtime to finalize the objects. For example:
static void TestFinally()
{
System.IO.FileStream file = null;
//Change the path to something that works on your machine.
System.IO.FileInfo fileInfo = new System.IO.FileInfo(@"C:\file.txt");
try
{
file = fileInfo.OpenWrite();
file.WriteByte(0xF);
}
finally
{
// Closing the file allows you to reopen it immediately - otherwise IOException is thrown.
if (file != null)
{
file.Close();
}
}
try
{
file = fileInfo.OpenWrite();
System.Console.WriteLine("OpenWrite() succeeded");
}
catch (System.IO.IOException)
{
System.Console.WriteLine("OpenWrite() failed");
}
}
If WriteByte()threw an exception, the code in the second try block that tries to reopen the file would fail if
file.Close() is not called, and the file would remain locked. Because finally blocks are executed even if an
exception is thrown, the finally block in the previous example allows for the file to be closed correctly and helps
avoid an error.
If no compatible catch block is found on the call stack after an exception is thrown, one of three things occurs:
If the exception is within a finalizer, the finalizer is aborted and the base finalizer, if any, is called.
If the call stack contains a static constructor, or a static field initializer, a TypeInitializationException is thrown,
with the original exception assigned to the InnerException property of the new exception.
If the start of the thread is reached, the thread is terminated.
See also
C# Programming Guide
Exceptions and Exception Handling
Exception Handling (C# Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
A try block is used by C# programmers to partition code that might be affected by an exception. Associated catch
blocks are used to handle any resulting exceptions. A finally block contains code that is run regardless of whether
or not an exception is thrown in the try block, such as releasing resources that are allocated in the try block. A
try block requires one or more associated catch blocks, or a finally block, or both.
The following examples show a try-catch statement, a try-finally statement, and a try-catch-finally
statement.
try
{
// Code to try goes here.
}
catch (SomeSpecificException ex)
{
// Code to handle the exception goes here.
// Only catch exceptions that you know how to handle.
// Never catch base class System.Exception without
// rethrowing it at the end of the catch block.
}
try
{
// Code to try goes here.
}
finally
{
// Code to execute after the try block goes here.
}
try
{
// Code to try goes here.
}
catch (SomeSpecificException ex)
{
// Code to handle the exception goes here.
}
finally
{
// Code to execute after the try (and possibly catch) blocks
// goes here.
}
Catch Blocks
A catch block can specify the type of exception to catch. The type specification is called an exception filter. The
exception type should be derived from Exception. In general, do not specify Exception as the exception filter unless
either you know how to handle all exceptions that might be thrown in the try block, or you have included a
throw statement at the end of your catch block.
Multiple catch blocks with different exception filters can be chained together. The catch blocks are evaluated
from top to bottom in your code, but only one catch block is executed for each exception that is thrown. The first
catch block that specifies the exact type or a base class of the thrown exception is executed. If no catch block
specifies a matching exception filter, a catch block that does not have a filter is selected, if one is present in the
statement. It is important to position catch blocks with the most specific (that is, the most derived) exception
types first.
You should catch exceptions when the following conditions are true:
You have a good understanding of why the exception might be thrown, and you can implement a specific
recovery, such as prompting the user to enter a new file name when you catch a FileNotFoundException
object.
You can create and throw a new, more specific exception.
You want to partially handle an exception before passing it on for additional handling. In the following
example, a catch block is used to add an entry to an error log before re-throwing the exception.
try
{
// Try to access a resource.
}
catch (System.UnauthorizedAccessException e)
{
// Call a custom error logging procedure.
LogError(e);
// Re-throw the error.
throw;
}
Finally Blocks
A finally block enables you to clean up actions that are performed in a try block. If present, the finally block
executes last, after the try block and any matched catch block. A finally block always runs, regardless of
whether an exception is thrown or a catch block matching the exception type is found.
The finally block can be used to release resources such as file streams, database connections, and graphics
handles without waiting for the garbage collector in the runtime to finalize the objects. See using Statement for
more information.
In the following example, the finally block is used to close a file that is opened in the try block. Notice that the
state of the file handle is checked before the file is closed. If the try block cannot open the file, the file handle still
has the value null and the finally block does not try to close it. Alternatively, if the file is opened successfully in
the try block, the finally block closes the open file.
System.IO.FileStream file = null;
System.IO.FileInfo fileinfo = new System.IO.FileInfo("C:\\file.txt");
try
{
file = fileinfo.OpenWrite();
file.WriteByte(0xF);
}
finally
{
// Check for null because OpenWrite might have failed.
if (file != null)
{
file.Close();
}
}
C# Language Specification
For more information, see Exceptions and The try statement in the C# Language Specification. The language
specification is the definitive source for C# syntax and usage.
See also
C# Reference
C# Programming Guide
Exceptions and Exception Handling
try-catch
try-finally
try-catch-finally
using Statement
Creating and Throwing Exceptions (C# Programming
Guide)
9/3/2020 • 3 minutes to read • Edit Online
Exceptions are used to indicate that an error has occurred while running the program. Exception objects that
describe an error are created and then thrown with the throw keyword. The runtime then searches for the most
compatible exception handler.
Programmers should throw exceptions when one or more of the following conditions are true:
The method cannot complete its defined functionality.
For example, if a parameter to a method has an invalid value:
class ProgramLog
{
System.IO.FileStream logFile = null;
void OpenLog(System.IO.FileInfo fileName, System.IO.FileMode mode) {}
void WriteLog()
{
if (!this.logFile.CanWrite)
{
throw new System.InvalidOperationException("Logfile cannot be read-only");
}
// Else write data to the log and return.
}
}
Exceptions contain a property named StackTrace. This string contains the name of the methods on the current call
stack, together with the file name and line number where the exception was thrown for each method. A StackTrace
object is created automatically by the common language runtime (CLR) from the point of the throw statement, so
that exceptions must be thrown from the point where the stack trace should begin.
All exceptions contain a property named Message. This string should be set to explain the reason for the exception.
Note that information that is sensitive to security should not be put in the message text. In addition to Message,
ArgumentException contains a property named ParamName that should be set to the name of the argument that
caused the exception to be thrown. In the case of a property setter, ParamName should be set to value .
Public and protected methods should throw exceptions whenever they cannot complete their intended functions.
The exception class that is thrown should be the most specific exception available that fits the error conditions.
These exceptions should be documented as part of the class functionality, and derived classes or updates to the
original class should retain the same behavior for backward compatibility.
New properties should only be added to the exception class when the data they provide is useful to resolving the
exception. If new properties are added to the derived exception class, ToString() should be overridden to return
the added information.
C# Language Specification
For more information, see Exceptions and The throw statement in the C# Language Specification. The language
specification is the definitive source for C# syntax and usage.
See also
C# Programming Guide
Exceptions and Exception Handling
Exception Hierarchy
Exception Handling
Compiler-Generated Exceptions (C# Programming
Guide)
9/3/2020 • 2 minutes to read • Edit Online
Some exceptions are thrown automatically by the .NET runtime when basic operations fail. These exceptions and
their error conditions are listed in the following table.
See also
C# Programming Guide
Exceptions and Exception Handling
Exception Handling
try-catch
try-finally
try-catch-finally
How to handle an exception using try/catch (C#
Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
The purpose of a try-catch block is to catch and handle an exception generated by working code. Some exceptions
can be handled in a catch block and the problem solved without the exception being re-thrown; however, more
often the only thing that you can do is make sure that the appropriate exception is thrown.
Example
In this example, IndexOutOfRangeException is not the most appropriate exception: ArgumentOutOfRangeException
makes more sense for the method because the error is caused by the index argument passed in by the caller.
class TestTryCatch
{
static int GetInt(int[] array, int index)
{
try
{
return array[index];
}
catch (System.IndexOutOfRangeException e) // CS0168
{
System.Console.WriteLine(e.Message);
// Set IndexOutOfRangeException to the new exception's InnerException.
throw new System.ArgumentOutOfRangeException("index parameter is out of range.", e);
}
}
}
Comments
The code that causes an exception is enclosed in the try block. A catch statement is added immediately after to
handle IndexOutOfRangeException , if it occurs. The catch block handles the IndexOutOfRangeException and throws
the more appropriate ArgumentOutOfRangeException exception instead. In order to provide the caller with as much
information as possible, consider specifying the original exception as the InnerException of the new exception.
Because the InnerException property is read-only, you must assign it in the constructor of the new exception.
See also
C# Programming Guide
Exceptions and Exception Handling
Exception Handling
How to execute cleanup code using finally (C#
Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
The purpose of a finally statement is to ensure that the necessary cleanup of objects, usually objects that are
holding external resources, occurs immediately, even if an exception is thrown. One example of such cleanup is
calling Close on a FileStream immediately after use instead of waiting for the object to be garbage collected by the
common language runtime, as follows:
file = fileInfo.OpenWrite();
file.WriteByte(0xF);
file.Close();
}
Example
To turn the previous code into a try-catch-finally statement, the cleanup code is separated from the working
code, as follows.
try
{
fileInfo = new System.IO.FileInfo("C:\\file.txt");
file = fileInfo.OpenWrite();
file.WriteByte(0xF);
}
catch(System.UnauthorizedAccessException e)
{
System.Console.WriteLine(e.Message);
}
finally
{
if (file != null)
{
file.Close();
}
}
}
Because an exception can occur at any time within the try block before the OpenWrite() call, or the OpenWrite()
call itself could fail, we are not guaranteed that the file is open when we try to close it. The finally block adds a
check to make sure that the FileStream object is not null before you call the Close method. Without the null
check, the finally block could throw its own NullReferenceException, but throwing exceptions in finally blocks
should be avoided if it is possible.
A database connection is another good candidate for being closed in a finally block. Because the number of
connections allowed to a database server is sometimes limited, you should close database connections as quickly
as possible. If an exception is thrown before you can close your connection, this is another case where using the
finally block is better than waiting for garbage collection.
See also
C# Programming Guide
Exceptions and Exception Handling
Exception Handling
using Statement
try-catch
try-finally
try-catch-finally
How to catch a non-CLS exception
9/3/2020 • 2 minutes to read • Edit Online
Some .NET languages, including C++/CLI, allow objects to throw exceptions that do not derive from Exception.
Such exceptions are called non-CLS exceptions or non-Exceptions. In C# you cannot throw non-CLS exceptions, but
you can catch them in two ways:
Within a catch (RuntimeWrappedException e) block.
By default, a Visual C# assembly catches non-CLS exceptions as wrapped exceptions. Use this method if you
need access to the original exception, which can be accessed through the
RuntimeWrappedException.WrappedException property. The procedure later in this topic explains how to
catch exceptions in this manner.
Within a general catch block (a catch block without an exception type specified) that is put after all other
catch blocks.
Use this method when you want to perform some action (such as writing to a log file) in response to non-
CLS exceptions, and you do not need access to the exception information. By default the common language
runtime wraps all exceptions. To disable this behavior, add this assembly-level attribute to your code,
typically in the AssemblyInfo.cs file:
[assembly: RuntimeCompatibilityAttribute(WrapNonExceptionThrows = false)] .
Example
The following example shows how to catch a non-CLS exception that was thrown from a class library written in
C++/CLI. Note that in this example, the C# client code knows in advance that the exception type being thrown is a
System.String. You can cast the RuntimeWrappedException.WrappedException property back its original type as
long as that type is accessible from your code.
try
{
// throws gcnew System::String(
// "I do not derive from System.Exception!");
myClass.TestThrow();
}
catch (RuntimeWrappedException e)
{
String s = e.WrappedException as String;
if (s != null)
{
Console.WriteLine(s);
}
}
See also
RuntimeWrappedException
Exceptions and Exception Handling
File system and the registry (C# Programming
Guide)
9/3/2020 • 2 minutes to read • Edit Online
The following articles show how to use C# and .NET to perform various basic operations on files, folders, and the
registry.
In this section
T IT L E DESC RIP T IO N
How to iterate through a directory tree Shows how to manually iterate through a directory tree.
How to get information about files, folders, and drives Shows how to retrieve information such as creation times and
size, about files, folders and drives.
How to create a file or folder Shows how to create a new file or folder.
How to copy, delete, and move files and folders (C# Shows how to copy, delete and move files and folders.
Programming Guide)
How to provide a progress dialog box for file operations Shows how to display a standard Windows progress dialog
for certain file operations.
How to read from a text file Shows how to read from a text file.
How to read a text file one line at a time Shows how to retrieve text from a file one line at a time.
How to create a key in the registry Shows how to write a key to the system registry.
Related sections
File and Stream I/O
How to copy, delete, and move files and folders (C# Programming Guide)
C# Programming Guide
System.IO
How to iterate through a directory tree (C#
Programming Guide)
9/3/2020 • 7 minutes to read • Edit Online
The phrase "iterate a directory tree" means to access each file in each nested subdirectory under a specified root
folder, to any depth. You do not necessarily have to open each file. You can just retrieve the name of the file or
subdirectory as a string , or you can retrieve additional information in the form of a System.IO.FileInfo or
System.IO.DirectoryInfo object.
NOTE
In Windows, the terms "directory" and "folder" are used interchangeably. Most documentation and user interface text uses
the term "folder," but .NET class libraries use the term "directory."
In the simplest case, in which you know for certain that you have access permissions for all directories under a
specified root, you can use the System.IO.SearchOption.AllDirectories flag. This flag returns all the nested
subdirectories that match the specified pattern. The following example shows how to use this flag.
root.GetDirectories("*.*", System.IO.SearchOption.AllDirectories);
The weakness in this approach is that if any one of the subdirectories under the specified root causes a
DirectoryNotFoundException or UnauthorizedAccessException, the whole method fails and returns no directories.
The same is true when you use the GetFiles method. If you have to handle these exceptions on specific subfolders,
you must manually walk the directory tree, as shown in the following examples.
When you manually walk a directory tree, you can handle the subdirectories first (pre-order traversal), or the files
first (post-order traversal). If you perform a pre-order traversal, you walk the whole tree under the current folder
before iterating through the files that are directly in that folder itself. The examples later in this document perform
post-order traversal, but you can easily modify them to perform pre-order traversal.
Another option is whether to use recursion or a stack-based traversal. The examples later in this document show
both approaches.
If you have to perform a variety of operations on files and folders, you can modularize these examples by
refactoring the operation into separate functions that you can invoke by using a single delegate.
NOTE
NTFS file systems can contain reparse points in the form of junction points, symbolic links, and hard links. .NET methods such
as GetFiles and GetDirectories will not return any subdirectories under a reparse point. This behavior guards against the risk
of entering into an infinite loop when two reparse points refer to each other. In general, you should use extreme caution
when you deal with reparse points to ensure that you do not unintentionally modify or delete files. If you require precise
control over reparse points, use platform invoke or native code to call the appropriate Win32 file system methods directly.
Example
The following example shows how to walk a directory tree by using recursion. The recursive approach is elegant
but has the potential to cause a stack overflow exception if the directory tree is large and deeply nested.
The particular exceptions that are handled, and the particular actions that are performed on each file or folder, are
provided as examples only. You should modify this code to meet your specific requirements. See the comments in
the code for more information.
catch (System.IO.DirectoryNotFoundException e)
{
Console.WriteLine(e.Message);
}
if (files != null)
{
foreach (System.IO.FileInfo fi in files)
{
// In this example, we only access the existing FileInfo object. If we
// want to open, delete or modify the file, then
// a try-catch block is required here to handle the case
// where the file has been deleted since the call to TraverseTree().
Console.WriteLine(fi.FullName);
}
Example
The following example shows how to iterate through files and folders in a directory tree without using recursion.
This technique uses the generic Stack<T> collection type, which is a last in first out (LIFO) stack.
The particular exceptions that are handled, and the particular actions that are performed on each file or folder, are
provided as examples only. You should modify this code to meet your specific requirements. See the comments in
the code for more information.
if (!System.IO.Directory.Exists(root))
{
throw new ArgumentException();
}
dirs.Push(root);
catch (UnauthorizedAccessException e)
{
Console.WriteLine(e.Message);
continue;
}
catch (System.IO.DirectoryNotFoundException e)
{
Console.WriteLine(e.Message);
continue;
}
// Perform the required action on each file here.
// Modify this block to perform your required task.
foreach (string file in files)
{
try
{
// Perform whatever action is required in your scenario.
System.IO.FileInfo fi = new System.IO.FileInfo(file);
Console.WriteLine("{0}: {1}, {2}", fi.Name, fi.Length, fi.CreationTime);
}
catch (System.IO.FileNotFoundException e)
{
// If file was deleted by a separate application
// or thread since the call to TraverseTree()
// then just continue.
Console.WriteLine(e.Message);
continue;
}
}
It is generally too time-consuming to test every folder to determine whether your application has permission to
open it. Therefore, the code example just encloses that part of the operation in a try/catch block. You can modify
the catch block so that when you are denied access to a folder, you try to elevate your permissions and then
access it again. As a rule, only catch those exceptions that you can handle without leaving your application in an
unknown state.
If you must store the contents of a directory tree, either in memory or on disk, the best option is to store only the
FullName property (of type string ) for each file. You can then use this string to create a new FileInfo or
DirectoryInfo object as necessary, or open any file that requires additional processing.
Robust Programming
Robust file iteration code must take into account many complexities of the file system. For more information on the
Windows file system, see NTFS overview.
See also
System.IO
LINQ and File Directories
File System and the Registry (C# Programming Guide)
How to get information about files, folders, and
drives (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
In .NET, you can access file system information by using the following classes:
System.IO.FileInfo
System.IO.DirectoryInfo
System.IO.DriveInfo
System.IO.Directory
System.IO.File
The FileInfo and DirectoryInfo classes represent a file or directory and contain properties that expose many of the
file attributes that are supported by the NTFS file system. They also contain methods for opening, closing, moving,
and deleting files and folders. You can create instances of these classes by passing a string that represents the
name of the file, folder, or drive in to the constructor:
You can also obtain the names of files, folders, or drives by using calls to DirectoryInfo.GetDirectories,
DirectoryInfo.GetFiles, and DriveInfo.RootDirectory.
The System.IO.Directory and System.IO.File classes provide static methods for retrieving information about
directories and files.
Example
The following example shows various ways to access information about files and folders.
class FileSysInfo
{
static void Main()
{
// You can also use System.Environment.GetLogicalDrives to
// obtain names of all logical drives on the computer.
System.IO.DriveInfo di = new System.IO.DriveInfo(@"C:\");
Console.WriteLine(di.TotalFreeSpace);
Console.WriteLine(di.VolumeLabel);
// Get the root directory and print out some information about it.
System.IO.DirectoryInfo dirInfo = di.RootDirectory;
Console.WriteLine(dirInfo.Attributes.ToString());
// Get the files in the directory and print out some information about them.
System.IO.FileInfo[] fileNames = dirInfo.GetFiles("*.*");
System.IO.Directory.SetCurrentDirectory(@"C:\Users\Public\TestFolder\");
currentDirName = System.IO.Directory.GetCurrentDirectory();
Console.WriteLine(currentDirName);
Robust Programming
When you process user-specified path strings, you should also handle exceptions for the following conditions:
The file name is malformed. For example, it contains invalid characters or only white space.
The file name is null.
The file name is longer than the system-defined maximum length.
The file name contains a colon (:).
If the application does not have sufficient permissions to read the specified file, the Exists method returns false
regardless of whether a path exists; the method does not throw an exception.
See also
System.IO
C# Programming Guide
File System and the Registry (C# Programming Guide)
How to create a file or folder (C# Programming
Guide)
9/3/2020 • 3 minutes to read • Edit Online
You can programmatically create a folder on your computer, create a subfolder, create a file in the subfolder, and
write data to the file.
Example
public class CreateFileOrFolder
{
static void Main()
{
// Specify a name for your top-level folder.
string folderName = @"c:\Top-Level Folder";
// You can write out the path name directly instead of using the Combine
// method. Combine just makes the process easier.
string pathString2 = @"c:\Top-Level Folder\SubFolder2";
// You can extend the depth of your path if you want to.
//pathString = System.IO.Path.Combine(pathString, "SubSubFolder");
// Create the subfolder. You can verify in File Explorer that you have this
// structure in the C: drive.
// Local Disk (C:)
// Top-Level Folder
// SubFolder
System.IO.Directory.CreateDirectory(pathString);
// This example uses a random string for the name, but you also can specify
// a particular name.
//string fileName = "MyNewFile.txt";
// Check that the file doesn't already exist. If it doesn't exist, create
// the file and write integers 0 - 99 to it.
// DANGER: System.IO.File.Create will overwrite the file if it already exists.
// This could happen even with random file names, although it is unlikely.
if (!System.IO.File.Exists(pathString))
{
using (System.IO.FileStream fs = System.IO.File.Create(pathString))
{
for (byte i = 0; i < 100; i++)
{
fs.WriteByte(i);
}
}
}
}
else
{
Console.WriteLine("File \"{0}\" already exists.", fileName);
return;
}
//0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
//30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
// 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 8
//3 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
}
If the folder already exists, CreateDirectory does nothing, and no exception is thrown. However, File.Create replaces
an existing file with a new file. The example uses an if - else statement to prevent an existing file from being
replaced.
By making the following changes in the example, you can specify different outcomes based on whether a file with a
certain name already exists. If such a file doesn't exist, the code creates one. If such a file exists, the code appends
data to that file.
Specify a non-random file name.
Replace the if - else statement with the using statement in the following code.
.NET Security
An instance of the SecurityException class may be thrown in partial-trust situations.
If you don't have permission to create the folder, the example throws an instance of the
UnauthorizedAccessException class.
See also
System.IO
C# Programming Guide
File System and the Registry (C# Programming Guide)
How to copy, delete, and move files and folders (C#
Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
The following examples show how to copy, move, and delete files and folders in a synchronous manner by using
the System.IO.File, System.IO.Directory, System.IO.FileInfo, and System.IO.DirectoryInfo classes from the System.IO
namespace. These examples do not provide a progress bar or any other user interface. If you want to provide a
standard progress dialog box, see How to provide a progress dialog box for file operations.
Use System.IO.FileSystemWatcher to provide events that will enable you to calculate the progress when operating
on multiple files. Another approach is to use platform invoke to call the relevant file-related methods in the
Windows Shell. For information about how to perform these file operations asynchronously, see Asynchronous File
I/O.
Example
The following example shows how to copy files and directories.
// Simple synchronous file copy operations with no user interface.
// To run this sample, first create the following directories and files:
// C:\Users\Public\TestFolder
// C:\Users\Public\TestFolder\test.txt
// C:\Users\Public\TestFolder\SubDir\test.txt
public class SimpleFileCopy
{
static void Main()
{
string fileName = "test.txt";
string sourcePath = @"C:\Users\Public\TestFolder";
string targetPath = @"C:\Users\Public\TestFolder\SubDir";
// Copy the files and overwrite destination files if they already exist.
foreach (string s in files)
{
// Use static Path methods to extract only the file name from the path.
fileName = System.IO.Path.GetFileName(s);
destFile = System.IO.Path.Combine(targetPath, fileName);
System.IO.File.Copy(s, destFile, true);
}
}
else
{
Console.WriteLine("Source path does not exist!");
}
Example
The following example shows how to move files and directories.
// Simple synchronous file move operations with no user interface.
public class SimpleFileMove
{
static void Main()
{
string sourceFile = @"C:\Users\Public\public\test.txt";
string destinationFile = @"C:\Users\Public\private\test.txt";
Example
The following example shows how to delete files and directories.
catch (System.IO.IOException e)
{
Console.WriteLine(e.Message);
}
}
See also
System.IO
C# Programming Guide
File System and the Registry (C# Programming Guide)
How to provide a progress dialog box for file operations
File and Stream I/O
Common I/O Tasks
How to provide a progress dialog box for file
operations (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
You can provide a standard dialog box that shows progress on file operations in Windows if you use the
CopyFile(String, String, UIOption) method in the Microsoft.VisualBasic namespace.
NOTE
Your computer might show different names or locations for some of the Visual Studio user interface elements in the
following instructions. The Visual Studio edition that you have and the settings that you use determine these elements. For
more information, see Personalizing the IDE.
Example
The following code copies the directory that sourcePath specifies into the directory that destinationPath
specifies. This code also provides a standard dialog box that shows the estimated amount of time remaining
before the operation finishes.
class FileProgress
{
static void Main()
{
// Specify the path to a folder that you want to copy. If the folder is small,
// you won't have time to see the progress dialog box.
string sourcePath = @"C:\Windows\symbols\";
// Choose a destination for the copied files.
string destinationPath = @"C:\TestFolder";
FileSystem.CopyDirectory(sourcePath, destinationPath,
UIOption.AllDialogs);
}
}
See also
File System and the Registry (C# Programming Guide)
How to write to a text file (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
These examples show various ways to write text to a file. The first two examples use static convenience methods on
the System.IO.File class to write each element of any IEnumerable<string> and a string to a text file. Example 3
shows how to add text to a file when you have to process each line individually as you write to the file. Examples 1-
3 overwrite all existing content in the file, but example 4 shows you how to append text to an existing file.
These examples all write string literals to files. If you want to format text written to a file, use the Format method or
C# string interpolation feature.
Example
class WriteTextFile
{
static void Main()
{
Robust Programming
The following conditions may cause an exception:
The file exists and is read-only.
The path name may be too long.
The disk may be full.
See also
C# Programming Guide
File System and the Registry (C# Programming Guide)
Sample: Save a collection to Application Storage
How to read from a text file (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
This example reads the contents of a text file by using the static methods ReadAllText and ReadAllLines from the
System.IO.File class.
For an example that uses StreamReader, see How to read a text file one line at a time.
NOTE
The files that are used in this example are created in the topic How to write to a text file.
Example
class ReadFromFile
{
static void Main()
{
// The files used in this example are created in the topic
// How to: Write to a Text File. You can change the path and
// file name to substitute text files of your own.
// Example #1
// Read the file as one string.
string text = System.IO.File.ReadAllText(@"C:\Users\Public\TestFolder\WriteText.txt");
// Example #2
// Read each line of the file into a string array. Each element
// of the array is one line of the file.
string[] lines = System.IO.File.ReadAllLines(@"C:\Users\Public\TestFolder\WriteLines2.txt");
.NET Security
Do not rely on the name of a file to determine the contents of the file. For example, the file myFile.cs might not be
a C# source file.
See also
System.IO
C# Programming Guide
File System and the Registry (C# Programming Guide)
How to read a text file one line at a time (C#
Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
This example reads the contents of a text file, one line at a time, into a string using the ReadLine method of the
StreamReader class. Each text line is stored into the string line and displayed on the screen.
Example
int counter = 0;
string line;
file.Close();
System.Console.WriteLine("There were {0} lines.", counter);
// Suspend the screen.
System.Console.ReadLine();
Robust Programming
The following conditions may cause an exception:
The file may not exist.
.NET Security
Do not make decisions about the contents of the file based on the name of the file. For example, the file myFile.cs
may not be a C# source file.
See also
System.IO
C# Programming Guide
File System and the Registry (C# Programming Guide)
How to create a key in the registry (C# Programming
Guide)
9/3/2020 • 2 minutes to read • Edit Online
This example adds the value pair, "Name" and "Isabella", to the current user's registry, under the key "Names".
Example
Microsoft.Win32.RegistryKey key;
key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey("Names");
key.SetValue("Name", "Isabella");
key.Close();
Robust Programming
Examine the registry structure to find a suitable location for your key. For example, you might want to open the
Software key of the current user, and create a key with your company's name. Then add the registry values to your
company's key.
The following conditions might cause an exception:
The name of the key is null.
The user does not have permissions to create registry keys.
The key name exceeds the 255-character limit.
The key is closed.
The registry key is read-only.
.NET Security
It is more secure to write data to the user folder — Microsoft.Win32.Registry.CurrentUser — rather than to the
local computer — Microsoft.Win32.Registry.LocalMachine .
When you create a registry value, you need to decide what to do if that value already exists. Another process,
perhaps a malicious one, may have already created the value and have access to it. When you put data in the
registry value, the data is available to the other process. To prevent this, use the.
Overload:Microsoft.Win32.RegistryKey.GetValue method. It returns null if the key does not already exist.
It is not secure to store secrets, such as passwords, in the registry as plain text, even if the registry key is protected
by access control lists (ACL).
See also
System.IO
C# Programming Guide
File System and the Registry (C# Programming Guide)
Read, write and delete from the registry with C#
Interoperability (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
Interoperability enables you to preserve and take advantage of existing investments in unmanaged code. Code
that runs under the control of the common language runtime (CLR) is called managed code, and code that runs
outside the CLR is called unmanaged code. COM, COM+, C++ components, ActiveX components, and Microsoft
Windows API are examples of unmanaged code.
.NET enables interoperability with unmanaged code through platform invoke services, the
System.Runtime.InteropServices namespace, C++ interoperability, and COM interoperability (COM interop).
In This Section
Interoperability Overview
Describes methods to interoperate between C# managed code and unmanaged code.
How to access Office interop objects by using C# features
Describes features that are introduced in Visual C# to facilitate Office programming.
How to use indexed properties in COM interop programming
Describes how to use indexed properties to access COM properties that have parameters.
How to use platform invoke to play a WAV file
Describes how to use platform invoke services to play a .wav sound file on the Windows operating system.
Walkthrough: Office Programming
Shows how to create an Excel workbook and a Word document that contains a link to the workbook.
Example COM Class
Demonstrates how to expose a C# class as a COM object.
C# Language Specification
For more information, see Basic concepts in the C# Language Specification. The language specification is the
definitive source for C# syntax and usage.
See also
Marshal.ReleaseComObject
C# Programming Guide
Interoperating with Unmanaged Code
Walkthrough: Office Programming
Interoperability Overview (C# Programming Guide)
9/3/2020 • 3 minutes to read • Edit Online
The topic describes methods to enable interoperability between C# managed code and unmanaged code.
Platform Invoke
Platform invoke is a service that enables managed code to call unmanaged functions that are implemented in
dynamic link libraries (DLLs), such as those in the Microsoft Windows API. It locates and invokes an exported
function and marshals its arguments (integers, strings, arrays, structures, and so on) across the interoperation
boundary as needed.
For more information, see Consuming Unmanaged DLL Functions and How to use platform invoke to play a WAV
file.
NOTE
The Common Language Runtime (CLR) manages access to system resources. Calling unmanaged code that is outside the
CLR bypasses this security mechanism, and therefore presents a security risk. For example, unmanaged code might call
resources in unmanaged code directly, bypassing CLR security mechanisms. For more information, see Security in .NET.
C++ Interop
You can use C++ interop, also known as It Just Works (IJW), to wrap a native C++ class so that it can be consumed
by code that is authored in C# or another .NET language. To do this, you write C++ code to wrap a native DLL or
COM component. Unlike other .NET languages, Visual C++ has interoperability support that enables managed and
unmanaged code to be located in the same application and even in the same file. You then build the C++ code by
using the /clr compiler switch to produce a managed assembly. Finally, you add a reference to the assembly in
your C# project and use the wrapped objects just as you would use other managed classes.
Exposing C# to COM
COM clients can consume C# types that have been correctly exposed. The basic steps to expose C# types are as
follows:
1. Add interop attributes in the C# project.
You can make an assembly COM visible by modifying Visual C# project properties. For more information,
see Assembly Information Dialog Box.
2. Generate a COM type library and register it for COM usage.
You can modify Visual C# project properties to automatically register the C# assembly for COM interop.
Visual Studio uses the Regasm.exe (Assembly Registration Tool), using the /tlb command-line switch,
which takes a managed assembly as input, to generate a type library. This type library describes the public
types in the assembly and adds registry entries so that COM clients can create managed classes.
For more information, see Exposing .NET Framework Components to COM and Example COM Class.
See also
Improving Interop Performance
Introduction to Interoperability between COM and .NET
Introduction to COM Interop in Visual Basic
Marshaling between Managed and Unmanaged Code
Interoperating with Unmanaged Code
C# Programming Guide
How to access Office interop objects (C#
Programming Guide)
9/3/2020 • 12 minutes to read • Edit Online
C# has features that simplify access to Office API objects. The new features include named and optional
arguments, a new type called dynamic , and the ability to pass arguments to reference parameters in COM
methods as if they were value parameters.
In this topic you will use the new features to write code that creates and displays a Microsoft Office Excel
worksheet. You will then write code to add an Office Word document that contains an icon that is linked to the
Excel worksheet.
To complete this walkthrough, you must have Microsoft Office Excel 2007 and Microsoft Office Word 2007, or
later versions, installed on your computer.
NOTE
Your computer might show different names or locations for some of the Visual Studio user interface elements in the
following instructions. The Visual Studio edition that you have and the settings that you use determine these elements. For
more information, see Personalizing the IDE.
To add references
1. In Solution Explorer , right-click your project's name and then click Add Reference . The Add Reference
dialog box appears.
2. On the Assemblies page, select Microsoft.Office.Interop.Word in the Component Name list, and
then hold down the CTRL key and select Microsoft.Office.Interop.Excel . If you do not see the assemblies,
you may need to ensure they are installed and displayed. See How to: Install Office Primary Interop
Assemblies.
3. Click OK .
To add necessary using directives
1. In Solution Explorer , right-click the Program.cs file and then click View Code .
2. Add the following using directives to the top of the code file:
2. Add the following code to the Main method to create a bankAccounts list that contains two accounts.
2. Add the following code at the end of DisplayInExcel . The code inserts values into the first two columns of
the first row of the worksheet.
3. Add the following code at the end of DisplayInExcel . The foreach loop puts the information from the list
of accounts into the first two columns of successive rows of the worksheet.
var row = 1;
foreach (var acct in accounts)
{
row++;
workSheet.Cells[row, "A"] = acct.ID;
workSheet.Cells[row, "B"] = acct.Balance;
}
4. Add the following code at the end of DisplayInExcel to adjust the column widths to fit the content.
workSheet.Columns[1].AutoFit();
workSheet.Columns[2].AutoFit();
Earlier versions of C# require explicit casting for these operations because ExcelApp.Columns[1] returns an
Object , and AutoFit is an Excel Range method. The following lines show the casting.
((Excel.Range)workSheet.Columns[1]).AutoFit();
((Excel.Range)workSheet.Columns[2]).AutoFit();
C# 4, and later versions, converts the returned Object to dynamic automatically if the assembly is
referenced by the -link compiler option or, equivalently, if the Excel Embed Interop Types property is set
to true. True is the default value for this property.
2. Press CTRL+F5.
An Excel worksheet appears that contains the data from the two accounts.
// The Add method has four reference parameters, all of which are
// optional. Visual C# allows you to omit arguments for them if
// the default values are what you want.
wordApp.Documents.Add();
In C# 3.0 and earlier versions of the language, the following more complex code is required.
static void CreateIconInWordDoc2008()
{
var wordApp = new Word.Application();
wordApp.Visible = true;
// The Add method has four parameters, all of which are optional.
// In Visual C# 2008 and earlier versions, an argument has to be sent
// for every parameter. Because the parameters are reference
// parameters of type object, you have to create an object variable
// for the arguments that represents 'no value'.
3. Add the following statement at the end of DisplayInExcel . The Copy method adds the worksheet to the
Clipboard.
// Put the spreadsheet contents on the clipboard. The Copy method has one
// optional parameter for specifying a destination. Because no argument
// is sent, the destination is the Clipboard.
workSheet.Range["A1:B3"].Copy();
4. Press CTRL+F5.
A Word document appears that contains an icon. Double-click the icon to bring the worksheet to the
foreground.
((Excel.Range)workSheet.Columns[1]).AutoFit();
((Excel.Range)workSheet.Columns[2]).AutoFit();
2. To change the default and use PIAs instead of embedding type information, expand the References node
in Solution Explorer and then select Microsoft.Office.Interop.Excel or
Microsoft.Office.Interop.Word .
3. If you cannot see the Proper ties window, press F4 .
4. Find Embed Interop Types in the list of properties, and change its value to False . Equivalently, you can
compile by using the -reference compiler option instead of -link at a command prompt.
The AutoFormat method has seven value parameters, all of which are optional. Named and optional
arguments enable you to provide arguments for none, some, or all of them. In the previous statement, an
argument is supplied for only one of the parameters, Format . Because Format is the first parameter in the
parameter list, you do not have to provide the parameter name. However, the statement might be easier to
understand if the parameter name is included, as is shown in the following code.
2. Press CTRL+F5 to see the result. Other formats are listed in the XlRangeAutoFormat enumeration.
3. Compare the statement in step 1 with the following code, which shows the arguments that are required in
C# 3.0 and earlier versions.
// The AutoFormat method has seven optional value parameters. The
// following call specifies a value for the first parameter, and uses
// the default values for the other six.
Example
The following code shows the complete example.
using System;
using System.Collections.Generic;
using System.Linq;
using Excel = Microsoft.Office.Interop.Excel;
using Word = Microsoft.Office.Interop.Word;
namespace OfficeProgramminWalkthruComplete
{
class Walkthrough
{
static void Main(string[] args)
{
// Create a list of accounts.
var bankAccounts = new List<Account>
{
new Account {
ID = 345678,
Balance = 541.27
},
new Account {
ID = 1230221,
Balance = -127.44
}
};
var row = 1;
foreach (var acct in accounts)
{
row++;
workSheet.Cells[row, "A"] = acct.ID;
workSheet.Cells[row, "B"] = acct.Balance;
}
workSheet.Columns[1].AutoFit();
workSheet.Columns[2].AutoFit();
// Put the spreadsheet contents on the clipboard. The Copy method has one
// optional parameter for specifying a destination. Because no argument
// is sent, the destination is the Clipboard.
workSheet.Range["A1:B3"].Copy();
}
// The Add method has four reference parameters, all of which are
// optional. Visual C# allows you to omit arguments for them if
// the default values are what you want.
wordApp.Documents.Add();
See also
Type.Missing
dynamic
Using Type dynamic
Named and Optional Arguments
How to use named and optional arguments in Office programming
How to use indexed properties in COM interop
programming (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
Indexed properties improve the way in which COM properties that have parameters are consumed in C#
programming. Indexed properties work together with other features in Visual C#, such as named and optional
arguments, a new type (dynamic), and embedded type information, to enhance Microsoft Office programming.
In earlier versions of C#, methods are accessible as properties only if the get method has no parameters and the
set method has one and only one value parameter. However, not all COM properties meet those restrictions. For
example, the Excel Range[Object, Object] property has a get accessor that requires a parameter for the name of
the range. In the past, because you could not access the Range property directly, you had to use the get_Range
method instead, as shown in the following example.
// Visual C# 2010.
var excelApp = new Excel.Application();
// . . .
Excel.Range targetRange = excelApp.Range["A1"];
NOTE
The previous example also uses the optional arguments feature, which enables you to omit Type.Missing .
Similarly to set the value of the Value property of a Range object in C# 3.0 and earlier, two arguments are
required. One supplies an argument for an optional parameter that specifies the type of the range value. The other
supplies the value for the Value property. The following examples illustrate these techniques. Both set the value of
the A1 cell to Name .
// Visual C# 2008.
targetRange.set_Value(Type.Missing, "Name");
// Or
targetRange.Value2 = "Name";
// Visual C# 2010.
targetRange.Value = "Name";
You cannot create indexed properties of your own. The feature only supports consumption of existing indexed
properties.
Example
The following code shows a complete example. For more information about how to set up a project that accesses
the Office API, see How to access Office interop objects by using C# features.
namespace IndexedProperties
{
class Program
{
static void Main(string[] args)
{
CSharp2010();
//CSharp2008();
}
See also
Named and Optional Arguments
dynamic
Using Type dynamic
How to use named and optional arguments in Office programming
How to access Office interop objects by using C# features
Walkthrough: Office Programming
How to use platform invoke to play a WAV file (C#
Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
The following C# code example illustrates how to use platform invoke services to play a WAV sound file on the
Windows operating system.
Example
This example code uses DllImportAttribute to import winmm.dll 's PlaySound method entry point as
Form1 PlaySound() . The example has a simple Windows Form with a button. Clicking the button opens a standard
windows OpenFileDialog dialog box so that you can open a file to play. When a wave file is selected, it is played by
using the PlaySound() method of the winmm.dll library. For more information about this method, see Using the
PlaySound function with Waveform-Audio Files. Browse and select a file that has a .wav extension, and then click
Open to play the wave file by using platform invoke. A text box shows the full path of the file selected.
The Open Files dialog box is filtered to show only files that have a .wav extension through the filter settings:
namespace WinSound
{
public partial class Form1 : Form
{
private TextBox textBox1;
private Button button1;
[System.Flags]
public enum PlaySoundFlags : int
{
SND_SYNC = 0x0000,
SND_ASYNC = 0x0001,
SND_NODEFAULT = 0x0002,
SND_LOOP = 0x0008,
SND_NOSTOP = 0x0010,
SND_NOWAIT = 0x00002000,
SND_FILENAME = 0x00020000,
SND_RESOURCE = 0x00040004
}
if (dialog1.ShowDialog() == DialogResult.OK)
{
textBox1.Text = dialog1.FileName;
PlaySound(dialog1.FileName, new System.IntPtr(), PlaySoundFlags.SND_SYNC);
}
}
See also
C# Programming Guide
Interoperability Overview
A Closer Look at Platform Invoke
Marshaling Data with Platform Invoke
Walkthrough: Office Programming (C# and Visual
Basic)
9/3/2020 • 11 minutes to read • Edit Online
Visual Studio offers features in C# and Visual Basic that improve Microsoft Office programming. Helpful C#
features include named and optional arguments and return values of type dynamic . In COM programming, you
can omit the ref keyword and gain access to indexed properties. Features in Visual Basic include auto-
implemented properties, statements in lambda expressions, and collection initializers.
Both languages enable embedding of type information, which allows deployment of assemblies that interact with
COM components without deploying primary interop assemblies (PIAs) to the user's computer. For more
information, see Walkthrough: Embedding Types from Managed Assemblies.
This walkthrough demonstrates these features in the context of Office programming, but many of these features
are also useful in general programming. In the walkthrough, you use an Excel Add-in application to create an Excel
workbook. Next, you create a Word document that contains a link to the workbook. Finally, you see how to enable
and disable the PIA dependency.
Prerequisites
You must have Microsoft Office Excel and Microsoft Office Word installed on your computer to complete this
walkthrough.
NOTE
Your computer might show different names or locations for some of the Visual Studio user interface elements in the
following instructions. The Visual Studio edition that you have and the settings that you use determine these elements. For
more information, see Personalizing the IDE.
using System.Collections.Generic;
using Excel = Microsoft.Office.Interop.Excel;
using Word = Microsoft.Office.Interop.Word;
Imports Microsoft.Office.Interop
class Account
{
public int ID { get; set; }
public double Balance { get; set; }
}
3. To create a bankAccounts list that contains two accounts, add the following code to the ThisAddIn_Startup
method in ThisAddIn.vb or ThisAddIn.cs. The list declarations use collection initializers. For more
information, see Collection Initializers.
With Me.Application
' Add a new Excel workbook.
.Workbooks.Add()
.Visible = True
.Range("A1").Value = "ID"
.Range("B1").Value = "Balance"
.Range("A2").Select()
Two new C# features are used in this method. Both of these features already exist in Visual Basic.
Method Add has an optional parameter for specifying a particular template. Optional parameters,
new in C# 4, enable you to omit the argument for that parameter if you want to use the parameter's
default value. Because no argument is sent in the previous example, Add uses the default template
and creates a new workbook. The equivalent statement in earlier versions of C# requires a
placeholder argument: excelApp.Workbooks.Add(Type.Missing) .
For more information, see Named and Optional Arguments.
The Range and Offset properties of the Range object use the indexed properties feature. This
feature enables you to consume these properties from COM types by using the following typical C#
syntax. Indexed properties also enable you to use the Value property of the Range object,
eliminating the need to use the Value2 property. The Value property is indexed, but the index is
optional. Optional arguments and indexed properties work together in the following example.
// In Visual C# 2008, you cannot access the Range, Offset, and Value
// properties directly.
excelApp.get_Range("A1").Value2 = "ID";
excelApp.ActiveCell.get_Offset(1, 0).Select();
You cannot create indexed properties of your own. The feature only supports consumption of
existing indexed properties.
For more information, see How to use indexed properties in COM interop programming.
2. Add the following code at the end of DisplayInExcel to adjust the column widths to fit the content.
excelApp.Columns[1].AutoFit();
excelApp.Columns[2].AutoFit();
' Add the following two lines at the end of the With statement.
.Columns(1).AutoFit()
.Columns(2).AutoFit()
These additions demonstrate another feature in C#: treating Object values returned from COM hosts such
as Office as if they have type dynamic. This happens automatically when Embed Interop Types is set to
its default value, True , or, equivalently, when the assembly is referenced by the -link compiler option. Type
dynamic allows late binding, already available in Visual Basic, and avoids the explicit casting required in C#
3.0 and earlier versions of the language.
For example, excelApp.Columns[1] returns an Object , and AutoFit is an Excel Range method. Without
dynamic , you must cast the object returned by excelApp.Columns[1] as an instance of Range before calling
method AutoFit .
For more information about embedding interop types, see procedures "To find the PIA reference" and "To
restore the PIA dependency" later in this topic. For more information about dynamic , see dynamic or Using
Type dynamic.
To invoke DisplayInExcel
1. Add the following code at the end of the ThisAddIn_StartUp method. The call to DisplayInExcel contains
two arguments. The first argument is the name of the list of accounts to be processed. The second
argument is a multiline lambda expression that defines how the data is to be processed. The ID and
balance values for each account are displayed in adjacent cells, and the row is displayed in red if the
balance is less than zero. For more information, see Lambda Expressions.
DisplayInExcel(bankAccounts,
Sub(account, cell)
' This multiline lambda expression sets custom
' processing rules for the bankAccounts.
cell.Value = account.ID
cell.Offset(0, 1).Value = account.Balance
2. To run the program, press F5. An Excel worksheet appears that contains the data from the accounts.
To add a Word document
1. Add the following code at the end of the ThisAddIn_StartUp method to create a Word document that
contains a link to the Excel workbook.
This code demonstrates several of the new features in C#: the ability to omit the ref keyword in COM
programming, named arguments, and optional arguments. These features already exist in Visual Basic. The
PasteSpecial method has seven parameters, all of which are defined as optional reference parameters.
Named and optional arguments enable you to designate the parameters you want to access by name and
to send arguments to only those parameters. In this example, arguments are sent to indicate that a link to
the workbook on the Clipboard should be created (parameter Link ) and that the link is to be displayed in
the Word document as an icon (parameter DisplayAsIcon ). Visual C# also enables you to omit the ref
keyword for these arguments.
To run the application
1. Press F5 to run the application. Excel starts and displays a table that contains the information from the two
accounts in bankAccounts . Then a Word document appears that contains a link to the Excel table.
To clean up the completed project
1. In Visual Studio, click Clean Solution on the Build menu. Otherwise, the add-in will run every time that you
open Excel on your computer.
To find the PIA reference
1. Run the application again, but do not click Clean Solution .
2. Select the Star t . Locate Microsoft Visual Studio <version> and open a developer command prompt.
3. Type ildasm in the Developer Command Prompt for Visual Studio window, and then press ENTER. The IL
DASM window appears.
4. On the File menu in the IL DASM window, select File > Open . Double-click Visual Studio <version> ,
and then double-click Projects . Open the folder for your project, and look in the bin/Debug folder for your
project name.dll. Double-click your project name.dll. A new window displays your project's attributes, in
addition to references to other modules and assemblies. Note that namespaces
Microsoft.Office.Interop.Excel and Microsoft.Office.Interop.Word are included in the assembly. By
default in Visual Studio, the compiler imports the types you need from a referenced PIA into your assembly.
For more information, see How to: View Assembly Contents.
5. Double-click the MANIFEST icon. A window appears that contains a list of assemblies that contain items
referenced by the project. Microsoft.Office.Interop.Excel and Microsoft.Office.Interop.Word are not
included in the list. Because the types your project needs have been imported into your assembly,
references to a PIA are not required. This makes deployment easier. The PIAs do not have to be present on
the user's computer, and because an application does not require deployment of a specific version of a PIA,
applications can be designed to work with multiple versions of Office, provided that the necessary APIs
exist in all versions.
Because deployment of PIAs is no longer necessary, you can create an application in advanced scenarios
that works with multiple versions of Office, including earlier versions. However, this works only if your code
does not use any APIs that are not available in the version of Office you are working with. It is not always
clear whether a particular API was available in an earlier version, and for that reason working with earlier
versions of Office is not recommended.
NOTE
Office did not publish PIAs before Office 2003. Therefore, the only way to generate an interop assembly for Office
2002 or earlier versions is by importing the COM reference.
See also
Auto-Implemented Properties (Visual Basic)
Auto-Implemented Properties (C#)
Collection Initializers
Object and Collection Initializers
Optional Parameters
Passing Arguments by Position and by Name
Named and Optional Arguments
Early and Late Binding
dynamic
Using Type dynamic
Lambda Expressions (Visual Basic)
Lambda Expressions (C#)
How to use indexed properties in COM interop programming
Walkthrough: Embedding Type Information from Microsoft Office Assemblies in Visual Studio
Walkthrough: Embedding Types from Managed Assemblies
Walkthrough: Creating Your First VSTO Add-in for Excel
COM Interop
Interoperability
Example COM Class (C# Programming Guide)
9/3/2020 • 2 minutes to read • Edit Online
The following is an example of a class that you would expose as a COM object. After this code has been placed in a
.cs file and added to your project, set the Register for COM Interop property to True . For more information, see
How to: Register a Component for COM Interop.
Exposing Visual C# objects to COM requires declaring a class interface, an events interface if it is required, and the
class itself. Class members must follow these rules to be visible to COM:
The class must be public.
Properties, methods, and events must be public.
Properties and methods must be declared on the class interface.
Events must be declared in the event interface.
Other public members in the class that are not declared in these interfaces will not be visible to COM, but they will
be visible to other .NET objects.
To expose properties and methods to COM, you must declare them on the class interface and mark them with a
DispId attribute, and implement them in the class. The order in which the members are declared in the interface
is the order used for the COM vtable.
To expose events from your class, you must declare them on the events interface and mark them with a DispId
attribute. The class should not implement this interface.
The class implements the class interface; it can implement more than one interface, but the first implementation
will be the default class interface. Implement the methods and properties exposed to COM here. They must be
marked public and must match the declarations in the class interface. Also, declare the events raised by the class
here. They must be marked public and must match the declarations in the events interface.
Example
using System.Runtime.InteropServices;
namespace project_name
{
[Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")]
public interface ComClass1Interface
{
}
[Guid("7BD20046-DF8C-44A6-8F6B-687FAA26FA71"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ComClass1Events
{
}
[Guid("0D53A3E8-E51A-49C7-944E-E72A2064F938"),
ClassInterface(ClassInterfaceType.None),
ComSourceInterfaces(typeof(ComClass1Events))]
public class ComClass1 : ComClass1Interface
{
}
}
See also
C# Programming Guide
Interoperability
Build Page, Project Designer (C#)
C# reference
9/3/2020 • 2 minutes to read • Edit Online
This section provides reference material about C# keywords, operators, special characters,
preprocessor directives, compiler options, and compiler errors and warnings.
In this section
C# Keywords
Provides links to information about C# keywords and syntax.
C# Operators
Provides links to information about C# operators and syntax.
C# Special Characters
Provides links to information about special contextual characters in C# and their usage.
C# Preprocessor Directives
Provides links to information about compiler commands for embedding in C# source code.
C# Compiler Options
Includes information about compiler options and how to use them.
C# Compiler Errors
Includes code snippets that demonstrate the cause and correction of C# compiler errors and
warnings.
C# Language Specification
The C# 6.0 language specification. This is a draft proposal for the C# 6.0 language. This
document will be refined through work with the ECMA C# standards committee. Version 5.0
has been released in December 2017 as the Standard ECMA-334 5th Edition document.
The features that have been implemented in C# versions after 6.0 are represented in
language specification proposals. These documents describe the deltas to the language spec
in order to add these new features. These are in draft proposal form. These specifications will
be refined and submitted to the ECMA standards committee for formal review and
incorporation into a future version of the C# Standard.
C# 7.0 Specification Proposals
There are a number of new features implemented in C# 7.0. They include pattern matching,
local functions, out variable declarations, throw expressions, binary literals, and digit
separators. This folder contains the specifications for each of those features.
C# 7.1 Specification Proposals
There are new features added in C# 7.1. First, you can write a Main method that returns
Task or Task<int> . This enables you to add the async modifier to Main . The default
expression can be used without a type in locations where the type can be inferred. Also, tuple
member names can be inferred. Finally, pattern matching can be used with generics.
C# 7.2 Specification Proposals
C# 7.2 added a number of small features. You can pass arguments by readonly reference
using the in keyword. There are a number of low-level changes to support compile-time
safety for Span and related types. You can use named arguments where later arguments are
positional, in some situations. The private protected access modifier enables you to specify
that callers are limited to derived types implemented in the same assembly. The ?: operator
can resolve to a reference to a variable. You can also format hexadecimal and binary numbers
using a leading digit separator.
C# 7.3 Specification Proposals
C# 7.3 is another point release that includes several small updates. You can use new
constraints on generic type parameters. Other changes make it easier to work with fixed
fields, including using stackalloc allocations. Local variables declared with the ref
keyword may be reassigned to refer to new storage. You can place attributes on auto-
implemented properties that target the compiler-generated backing field. Expression
variables can be used in initializers. Tuples can be compared for equality (or inequality). There
have also been some improvements to overload resolution.
C# 8.0 Specification Proposals
C# 8.0 is available with .NET Core 3.0. The features include nullable reference types, recursive
pattern matching, default interface methods, async streams, ranges and indexes, pattern
based using and using declarations, null coalescing assignment, and readonly instance
members.
Related sections
Using the Visual Studio Development Environment for C#
Provides links to conceptual and task topics that describe the IDE and Editor.
C# Programming Guide
Includes information about how to use the C# programming language.
C# language versioning
9/3/2020 • 4 minutes to read • Edit Online
The latest C# compiler determines a default language version based on your project's target framework or
frameworks. Visual Studio doesn't provide a UI to change the value, but you can change it by editing the csproj
file. The choice of default ensures that you use the latest language version compatible with your target
framework. You benefit from access to the latest language features compatible with your project's target. This
default choice also ensures you don't use a language that requires types or runtime behavior not available in
your target framework. Choosing a language version newer than the default can cause hard to diagnose
compile-time and runtime errors.
The rules in this article apply to the compiler delivered with Visual Studio 2019 or the .NET Core 3.0 SDK. The C#
compilers that are part of the Visual Studio 2017 installation or earlier .NET Core SDK versions target C# 7.0 by
default.
C# 8.0 (and higher) is supported only on .NET Core 3.x and newer versions. Many of the newest features require
library and runtime features introduced in .NET Core 3.x:
Default interface implementation requires new features in the .NET Core 3.0 CLR.
Async streams require the new types System.IAsyncDisposable,
System.Collections.Generic.IAsyncEnumerable<T>, and System.Collections.Generic.IAsyncEnumerator<T>.
Indices and ranges require the new types System.Index and System.Range.
Nullable reference types make use of several attributes to provide better warnings. Those attributes were
added in .NET Core 3.0. Other target frameworks haven't been annotated with any of these attributes. That
means nullable warnings may not accurately reflect potential issues.
Defaults
The compiler determines a default based on these rules:
When your project targets a preview framework that has a corresponding preview language version, the
language version used is the preview language version. You use the latest features with that preview in any
environment, without affecting projects that target a released .NET Core version.
TIP
To know what language version you're currently using, put #error version (case sensitive) in your code. This makes the
compiler produce a diagnostic, CS8304, with a message containing the compiler version being used and the current
selected language version.
Override a default
If you must specify your C# version explicitly, you can do so in several ways:
Manually edit your project file.
Set the language version for multiple projects in a subdirectory.
Configure the -langversion compiler option.
Edit the project file
You can set the language version in your project file. For example, if you explicitly want access to preview
features, add an element like this:
<PropertyGroup>
<LangVersion>preview</LangVersion>
</PropertyGroup>
The value preview uses the latest available preview C# language version that your compiler supports.
Configure multiple projects
To configure multiple projects, you can create a Director y.Build.props file that contains the <LangVersion>
element. You typically do that in your solution directory. Add the following to a Director y.Build.props file in
your solution directory:
<Project>
<PropertyGroup>
<LangVersion>preview</LangVersion>
</PropertyGroup>
</Project>
Builds in all subdirectories of the directory containing that file will use the preview C# version. For more
information, see the article on Customize your build.
VA L UE M EA N IN G
preview The compiler accepts all valid language syntax from the latest
preview version.
latest The compiler accepts syntax from the latest released version
of the compiler (including minor version).
latestMajor ( default ) The compiler accepts syntax from the latest released major
version of the compiler.
VA L UE M EA N IN G
ISO-2 (or 2 ) The compiler accepts only syntax that is included in ISO/IEC
23270:2006 C# (2.0).
ISO-1 (or 1 ) The compiler accepts only syntax that is included in ISO/IEC
23270:2003 C# (1.0/1.2).
TIP
Open the Developer Command Prompt for Visual Studio, and run the following command to see the listing of language
versions available on your machine.
csc -langversion:?
Questioning the -langversion compile option like this, will print something similar to the following:
Value types and reference types are the two main categories of C# types. A variable of a value type contains
an instance of the type. This differs from a variable of a reference type, which contains a reference to an
instance of the type. By default, on assignment, passing an argument to a method, and returning a method
result, variable values are copied. In the case of value-type variables, the corresponding type instances are
copied. The following example demonstrates that behavior:
using System;
MutateAndDisplay(p2);
Console.WriteLine($"{nameof(p2)} after passing to a method: {p2}");
}
As the preceding example shows, operations on a value-type variable affect only that instance of the value
type, stored in the variable.
If a value type contains a data member of a reference type, only the reference to the instance of the reference
type is copied when a value-type instance is copied. Both the copy and original value-type instance have
access to the same reference-type instance. The following example demonstrates that behavior:
using System;
using System.Collections.Generic;
public TaggedInteger(int n)
{
Number = n;
tags = new List<string>();
}
var n2 = n1;
n2.Number = 7;
n2.AddTag("B");
NOTE
To make your code less error-prone and more robust, define and use immutable value types. This article uses mutable
value types only for demonstration purposes.
C# language specification
For more information, see the following sections of the C# language specification:
Value types
Simple types
Variables
See also
C# reference
System.ValueType
Reference types
Integral numeric types (C# reference)
4/21/2020 • 3 minutes to read • Edit Online
The integral numeric types represent integer numbers. All integral numeric types are value types.
They are also simple types and can be initialized with literals. All integral numeric types support
arithmetic, bitwise logical, comparison, and equality operators.
C # T Y P E/ K EY W O RD RA N GE SIZ E . N ET T Y P E
In the preceding table, each C# type keyword from the leftmost column is an alias for the
corresponding .NET type. They are interchangeable. For example, the following declarations
declare variables of the same type:
int a = 123;
System.Int32 b = 123;
The default value of each integral type is zero, 0 . Each of the integral types has the MinValue and
MaxValue constants that provide the minimum and maximum value of that type.
Integer literals
Integer literals can be
decimal: without any prefix
hexadecimal: with the 0x or 0X prefix
binary: with the 0b or 0B prefix (available in C# 7.0 and later)
The following code demonstrates an example of each:
The preceding example also shows the use of _ as a digit separator, which is supported starting
with C# 7.0. You can use the digit separator with all kinds of numeric literals.
The type of an integer literal is determined by its suffix as follows:
If the literal has no suffix, its type is the first of the following types in which its value can be
represented: int , uint , long , ulong .
If the literal is suffixed by U or u , its type is the first of the following types in which its
value can be represented: uint , ulong .
If the literal is suffixed by L or l , its type is the first of the following types in which its
value can be represented: long , ulong .
NOTE
You can use the lowercase letter l as a suffix. However, this generates a compiler warning
because the letter l can be confused with the digit 1 . Use L for clarity.
byte a = 17;
byte b = 300; // CS0031: Constant value '300' cannot be converted to a 'byte'
As the preceding example shows, if the literal's value is not within the range of the destination
type, a compiler error CS0031 occurs.
You can also use a cast to convert the value represented by an integer literal to the type other
than the determined type of the literal:
Conversions
You can convert any integral numeric type to any other integral numeric type. If the destination
type can store all values of the source type, the conversion is implicit. Otherwise, you need to use
a cast expression to perform an explicit conversion. For more information, see Built-in numeric
conversions.
C# language specification
For more information, see the following sections of the C# language specification:
Integral types
Integer literals
See also
C# reference
Value types
Floating-point types
Standard numeric format strings
Numerics in .NET
Floating-point numeric types (C# reference)
9/3/2020 • 3 minutes to read • Edit Online
The floating-point numeric types represent real numbers. All floating-point numeric types are value types.
They are also simple types and can be initialized with literals. All floating-point numeric types support
arithmetic, comparison, and equality operators.
A P P RO XIM AT E
C # T Y P E/ K EY W O RD RA N GE P REC ISIO N SIZ E . N ET T Y P E
In the preceding table, each C# type keyword from the leftmost column is an alias for the corresponding
.NET type. They are interchangeable. For example, the following declarations declare variables of the same
type:
double a = 12.3;
System.Double b = 12.3;
The default value of each floating-point type is zero, 0 . Each of the floating-point types has the MinValue
and MaxValue constants that provide the minimum and maximum finite value of that type. The float and
double types also provide constants that represent not-a-number and infinity values. For example, the
double type provides the following constants: Double.NaN, Double.NegativeInfinity, and
Double.PositiveInfinity.
Because the decimal type has more precision and a smaller range than both float and double , it's
appropriate for financial and monetary calculations.
You can mix integral types and the float and double types in an expression. In this case, integral types are
implicitly converted to one of the floating-point types and, if necessary, the float type is implicitly
converted to double . The expression is evaluated as follows:
If there is double type in the expression, the expression evaluates to double , or to bool in relational and
equality comparisons.
If there is no double type in the expression, the expression evaluates to float , or to bool in relational
and equality comparisons.
You can also mix integral types and the decimal type in an expression. In this case, integral types are
implicitly converted to the decimal type and the expression evaluates to decimal , or to bool in relational
and equality comparisons.
You cannot mix the decimal type with the float and double types in an expression. In this case, if you
want to perform arithmetic, comparison, or equality operations, you must explicitly convert the operands
either from or to the decimal type, as the following example shows:
double a = 1.0;
decimal b = 2.1m;
Console.WriteLine(a + (double)b);
Console.WriteLine((decimal)a + b);
You can use either standard numeric format strings or custom numeric format strings to format a floating-
point value.
Real literals
The type of a real literal is determined by its suffix as follows:
The literal without suffix or with the d or D suffix is of type double
The literal with the f or F suffix is of type float
The literal with the m or M suffix is of type decimal
The following code demonstrates an example of each:
double d = 3D;
d = 4d;
d = 3.934_001;
float f = 3_000.5F;
f = 5.4f;
The preceding example also shows the use of _ as a digit separator, which is supported starting with C#
7.0. You can use the digit separator with all kinds of numeric literals.
You can also use scientific notation, that is, specify an exponent part of a real literal, as the following example
shows:
double d = 0.42e2;
Console.WriteLine(d); // output 42
float f = 134.45E-2f;
Console.WriteLine(f); // output: 1.3445
decimal m = 1.5E6m;
Console.WriteLine(m); // output: 1500000
Conversions
There is only one implicit conversion between floating-point numeric types: from float to double .
However, you can convert any floating-point type to any other floating-point type with the explicit cast. For
more information, see Built-in numeric conversions.
C# language specification
For more information, see the following sections of the C# language specification:
Floating-point types
The decimal type
Real literals
See also
C# reference
Value types
Integral types
Standard numeric format strings
Numerics in .NET
System.Numerics.Complex
Built-in numeric conversions (C# reference)
9/3/2020 • 4 minutes to read • Edit Online
C# provides a set of integral and floating-point numeric types. There exists a conversion between any two
numeric types, either implicit or explicit. You must use a cast expression to perform an explicit conversion.
F RO M TO
float double
NOTE
The implicit conversions from int , uint , long , or ulong to float and from long or ulong to double may
cause a loss of precision, but never a loss of an order of magnitude. The other implicit numeric conversions never lose any
information.
There are no implicit conversions between the decimal type and the float or double types.
A value of a constant expression of type int (for example, a value represented by an integer literal) can be
implicitly converted to sbyte , byte , short , ushort , uint , or ulong , if it's within the range of the
destination type:
byte a = 13;
byte b = 300; // CS0031: Constant value '300' cannot be converted to a 'byte'
As the preceding example shows, if the constant value is not within the range of the destination type, a
compiler error CS0031 occurs.
F RO M TO
byte sbyte
NOTE
An explicit numeric conversion might result in data loss or throw an exception, typically an OverflowException.
When you convert float or double to decimal , the source value is converted to decimal representation
and rounded to the nearest number after the 28th decimal place if required. Depending on the value of the
source value, one of the following results may occur:
If the source value is too small to be represented as a decimal , the result becomes zero.
If the source value is NaN (not a number), infinity, or too large to be represented as a decimal , an
OverflowException is thrown.
When you convert decimal to float or double , the source value is rounded to the nearest float or
double value, respectively.
C# language specification
For more information, see the following sections of the C# language specification:
Implicit numeric conversions
Explicit numeric conversions
See also
C# reference
Casting and type conversions
bool (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
The bool type keyword is an alias for the .NET System.Boolean structure type that represents a Boolean value,
which can be either true or false .
To perform logical operations with values of the bool type, use Boolean logical operators. The bool type is the
result type of comparison and equality operators. A bool expression can be a controlling conditional expression in
the if, do, while, and for statements and in the conditional operator ?: .
The default value of the bool type is false .
Literals
You can use the true and false literals to initialize a bool variable or to pass a bool value:
Conversions
C# provides only two conversions that involve the bool type. Those are an implicit conversion to the
corresponding nullable bool? type and an explicit conversion from the bool? type. However, .NET provides
additional methods that you can use to convert to or from the bool type. For more information, see the
Converting to and from Boolean values section of the System.Boolean API reference page.
C# language specification
For more information, see The bool type section of the C# language specification.
See also
C# reference
Value types
true and false operators
char (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
The char type keyword is an alias for the .NET System.Char structure type that represents a Unicode UTF-16
character.
TYPE RA N GE SIZ E . N ET T Y P E
Literals
You can specify a char value with:
a character literal.
a Unicode escape sequence, which is \u followed by the four-symbol hexadecimal representation of a
character code.
a hexadecimal escape sequence, which is \x followed by the hexadecimal representation of a character code.
As the preceding example shows, you can also cast the value of a character code into the corresponding char
value.
NOTE
In the case of a Unicode escape sequence, you must specify all four hexadecimal digits. That is, \u006A is a valid escape
sequence, while \u06A and \u6A are not valid.
In the case of a hexadecimal escape sequence, you can omit the leading zeros. That is, the \x006A , \x06A , and \x6A
escape sequences are valid and correspond to the same character.
Conversions
The char type is implicitly convertible to the following integral types: ushort , int , uint , long , and ulong .
It's also implicitly convertible to the built-in floating-point numeric types: float , double , and decimal . It's
explicitly convertible to sbyte , byte , and short integral types.
There are no implicit conversions from other types to the char type. However, any integral or floating-point
numeric type is explicitly convertible to char .
C# language specification
For more information, see the Integral types section of the C# language specification.
See also
C# reference
Value types
Strings
System.Text.Rune
Character encoding in .NET
Enumeration types (C# reference)
4/21/2020 • 3 minutes to read • Edit Online
An enumeration type (or enum type) is a value type defined by a set of named constants of the underlying
integral numeric type. To define an enumeration type, use the enum keyword and specify the names of enum
members:
enum Season
{
Spring,
Summer,
Autumn,
Winter
}
By default, the associated constant values of enum members are of type int ; they start with zero and
increase by one following the definition text order. You can explicitly specify any other integral numeric type
as an underlying type of an enumeration type. You can also explicitly specify the associated constant values,
as the following example shows:
You cannot define a method inside the definition of an enumeration type. To add functionality to an
enumeration type, create an extension method.
The default value of an enumeration type E is the value produced by expression (E)0 , even if zero doesn't
have the corresponding enum member.
You use an enumeration type to represent a choice from a set of mutually exclusive values or a combination
of choices. To represent a combination of choices, define an enumeration type as bit flags.
var a = (Days)37;
Console.WriteLine(a);
// Output:
// Monday, Wednesday, Saturday
}
}
For more information and examples, see the System.FlagsAttribute API reference page and the Non-exclusive
members and the Flags attribute section of the System.Enum API reference page.
Conversions
For any enumeration type, there exist explicit conversions between the enumeration type and its underlying
integral type. If you cast an enum value to its underlying type, the result is the associated integral value of an
enum member.
public enum Season
{
Spring,
Summer,
Autumn,
Winter
}
var b = (Season)1;
Console.WriteLine(b); // output: Summer
var c = (Season)4;
Console.WriteLine(c); // output: 4
}
}
Use the Enum.IsDefined method to determine whether an enumeration type contains an enum member with
the certain associated value.
For any enumeration type, there exist boxing and unboxing conversions to and from the System.Enum type,
respectively.
C# language specification
For more information, see the following sections of the C# language specification:
Enums
Enum values and operations
Enumeration logical operators
Enumeration comparison operators
Explicit enumeration conversions
Implicit enumeration conversions
See also
C# reference
Enumeration format strings
Design guidelines - Enum design
Design guidelines - Enum naming conventions
switch statement
Structure types (C# reference)
9/3/2020 • 7 minutes to read • Edit Online
A structure type (or struct type) is a value type that can encapsulate data and related functionality. You
use the struct keyword to define a structure type:
Structure types have value semantics. That is, a variable of a structure type contains an instance of the
type. By default, variable values are copied on assignment, passing an argument to a method, and
returning a method result. In the case of a structure-type variable, an instance of the type is copied. For
more information, see Value types.
Typically, you use structure types to design small data-centric types that provide little or no behavior.
For example, .NET uses structure types to represent a number (both integer and real), a Boolean value,
a Unicode character, a time instance. If you're focused on the behavior of a type, consider defining a
class. Class types have reference semantics. That is, a variable of a class type contains a reference to an
instance of the type, not the instance itself.
Because structure types have value semantics, we recommend you to define immutable structure
types.
readonly struct
Beginning with C# 7.2, you use the readonly modifier to declare that a structure type is immutable:
NOTE
In a readonly struct, a data member of a mutable reference type still can mutate its own state. For example,
you can't replace a List<T> instance, but you can add new elements to it.
Within a readonly instance member, you can't assign to structure's instance fields. However, a
readonly member can call a non- readonly member. In that case the compiler creates a copy of the
structure instance and calls the non- readonly member on that copy. As a result, the original structure
instance is not modified.
Typically, you apply the readonly modifier to the following kinds of instance members:
methods:
You can also apply the readonly modifier to methods that override methods declared in
System.Object:
If you need to apply the readonly modifier to both accessors of a property or indexer, apply it in
the declaration of the property or indexer.
NOTE
The compiler declares a get accessor of an auto-implemented property as readonly , regardless of
presence of the readonly modifier in a property declaration.
You can't apply the readonly modifier to static members of a structure type.
The compiler may make use of the readonly modifier for performance optimizations. For more
information, see Write safe and efficient C# code.
In the case of the built-in value types, use the corresponding literals to specify a value of the type.
ref struct
Beginning with C# 7.2, you can use the ref modifier in the declaration of a structure type. Instances of
a ref struct type are allocated on the stack and can't escape to the managed heap. To ensure that, the
compiler limits the usage of ref struct types as follows:
A ref struct can't be the element type of an array.
A ref struct can't be a declared type of a field of a class or a non- ref struct.
A ref struct can't implement interfaces.
A ref struct can't be boxed to System.ValueType or System.Object.
A ref struct can't be a type argument.
A ref struct variable can't be captured by a lambda expression or a local function.
A ref struct variable can't be used in an async method. However, you can use ref struct
variables in synchronous methods, for example, in those that return Task or Task<TResult>.
A ref struct variable can't be used in iterators.
Typically, you define a ref struct type when you need a type that also includes data members of ref
struct types:
To declare a ref struct as readonly , combine the readonly and ref modifiers in the type
declaration (the readonly modifier must come before the ref modifier):
Conversions
For any structure type (except ref struct types), there exist boxing and unboxing conversions to and
from the System.ValueType and System.Object types. There exist also boxing and unboxing
conversions between a structure type and any interface that it implements.
C# language specification
For more information, see the Structs section of the C# language specification.
For more information about features introduced in C# 7.2 and later, see the following feature proposal
notes:
Readonly structs
Readonly instance members
Compile-time safety for ref-like types
See also
C# reference
Design guidelines - Choosing between class and struct
Design guidelines - Struct design
Classes and structs
Tuple types (C# reference)
9/3/2020 • 8 minutes to read • Edit Online
Available in C# 7.0 and later, the tuples feature provides concise syntax to group multiple data elements in a
lightweight data structure. The following example shows how you can declare a tuple variable, initialize it, and
access its data members:
As the preceding example shows, to define a tuple type, you specify types of all its data members and,
optionally, the field names. You cannot define methods in a tuple type, but you can use the methods provided by
.NET, as the following example shows:
Beginning with C# 7.3, tuple types support equality operators == and != . For more information, see the Tuple
equality section.
Tuple types are value types; tuple elements are public fields. That makes tuples mutable value types.
NOTE
The tuples feature requires the System.ValueTuple type and related generic types (for example,
System.ValueTuple<T1,T2>), which are available in .NET Core and .NET Framework 4.7 and later. To use tuples in a project
that targets .NET Framework 4.6.2 or earlier, add the NuGet package System.ValueTuple to the project.
var t =
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 26);
Console.WriteLine(t.Item26); // output: 26
As the preceding example shows, you can work with the returned tuple instance directly or deconstruct it in
separate variables.
You can also use tuple types instead of anonymous types; for example, in LINQ queries. For more information,
see Choosing between anonymous and tuple types.
Typically, you use tuples to group loosely related data elements. That is usually useful within private and internal
utility methods. In the case of public API, consider defining a class or a structure type.
Beginning with C# 7.1, if you don't specify a field name, it may be inferred from the name of the corresponding
variable in a tuple initialization expression, as the following example shows:
var sum = 4.5;
var count = 3;
var t = (sum, count);
Console.WriteLine($"Sum of {t.count} elements is {t.sum}.");
That's known as tuple projection initializers. The name of a variable isn't projected onto a tuple field name in the
following cases:
The candidate name is a member name of a tuple type, for example, Item3 , ToString , or Rest .
The candidate name is a duplicate of another tuple field name, either explicit or implicit.
In those cases you either explicitly specify the name of a field or access a field by its default name.
The default names of tuple fields are Item1 , Item2 , Item3 and so on. You can always use the default name of a
field, even when a field name is specified explicitly or inferred, as the following example shows:
var a = 1;
var t = (a, b: 2, 3);
Console.WriteLine($"The 1st element is {t.Item1} (same as {t.a}).");
Console.WriteLine($"The 2nd element is {t.Item2} (same as {t.b}).");
Console.WriteLine($"The 3rd element is {t.Item3}.");
// Output:
// The 1st element is 1 (same as 1).
// The 2nd element is 2 (same as 2).
// The 3rd element is 3.
Tuple assignment and tuple equality comparisons don't take field names into account.
At compile time, the compiler replaces non-default field names with the corresponding default names. As a
result, explicitly specified or inferred field names aren't available at run time.
You can also use the assignment operator = to deconstruct a tuple instance in separate variables. You can do
that in one of the following ways:
Explicitly declare the type of each variable inside parentheses:
Use the var keyword outside the parentheses to declare implicitly typed variables and let the compiler
infer their types:
For more information about deconstruction of tuples and other types, see Deconstructing tuples and other
types.
Tuple equality
Beginning with C# 7.3, tuple types support the == and != operators. These operators compare members of
the left-hand operand with the corresponding members of the right-hand operand following the order of tuple
elements.
As the preceding example shows, the == and != operations don't take into account tuple field names.
Two tuples are comparable when both of the following conditions are satisfied:
Both tuples have the same number of elements. For example, t1 != t2 doesn't compile if t1 and t2 have
different numbers of elements.
For each tuple position, the corresponding elements from the left-hand and right-hand tuple operands are
comparable with the == and != operators. For example, (1, (2, 3)) == ((1, 2), 3) doesn't compile
because 1 is not comparable with (1, 2) .
The == and != operators compare tuples in short-circuiting way. That is, an operation stops as soon as it
meets a pair of non equal elements or reaches the ends of tuples. However, before any comparison, all tuple
elements are evaluated, as the following example shows:
int Display(int s)
{
Console.WriteLine(s);
return s;
}
// Output:
// 1
// 2
// 3
// 4
// False
Tuples vs System.Tuple
C# tuples, which are backed by System.ValueTuple types, are different from tuples that are represented by
System.Tuple types. The main differences are as follows:
ValueTuple types are value types. Tuple types are reference types.
ValueTuple types are mutable. Tuple types are immutable.
Data members of ValueTuple types are fields. Data members of Tuple types are properties.
C# language specification
For more information, see the following feature proposal notes:
Infer tuple names (aka. tuple projection initializers)
Support for == and != on tuple types
See also
C# reference
Value types
Choosing between anonymous and tuple types
System.ValueTuple
Nullable value types (C# reference)
4/21/2020 • 7 minutes to read • Edit Online
A nullable value type T? represents all values of its underlying value type T and an additional null value. For
example, you can assign any of the following three values to a bool? variable: true , false , or null . An
underlying value type T cannot be a nullable value type itself.
NOTE
C# 8.0 introduces the nullable reference types feature. For more information, see Nullable reference types. The nullable
value types are available beginning with C# 2.
Any nullable value type is an instance of the generic System.Nullable<T> structure. You can refer to a nullable
value type with an underlying type T in any of the following interchangeable forms: Nullable<T> or T? .
You typically use a nullable value type when you need to represent the undefined value of an underlying value
type. For example, a Boolean, or bool , variable can only be either true or false . However, in some
applications a variable value can be undefined or missing. For example, a database field may contain true or
false , or it may contain no value at all, that is, NULL . You can use the bool? type in that scenario.
double? pi = 3.14;
char? letter = 'a';
int m2 = 10;
int? m = m2;
The default value of a nullable value type represents null , that is, it's an instance whose
Nullable<T>.HasValue property returns false .
You always can use the following read-only properties to examine and get a value of a nullable value type
variable:
Nullable<T>.HasValue indicates whether an instance of a nullable value type has a value of its
underlying type.
Nullable<T>.Value gets the value of an underlying type if HasValue is true . If HasValue is false , the
Value property throws an InvalidOperationException.
The following example uses the HasValue property to test whether the variable contains a value before
displaying it:
int? b = 10;
if (b.HasValue)
{
Console.WriteLine($"b is {b.Value}");
}
else
{
Console.WriteLine("b does not have a value");
}
// Output:
// b is 10
You can also compare a variable of a nullable value type with null instead of using the HasValue property, as
the following example shows:
int? c = 7;
if (c != null)
{
Console.WriteLine($"c is {c.Value}");
}
else
{
Console.WriteLine("c does not have a value");
}
// Output:
// c is 7
int? c = null;
int d = c ?? -1;
Console.WriteLine($"d is {d}"); // output: d is -1
If you want to use the default value of the underlying value type in place of null , use the
Nullable<T>.GetValueOrDefault() method.
You can also explicitly cast a nullable value type to a non-nullable type, as the following example shows:
int? n = null;
At run time, if the value of a nullable value type is null , the explicit cast throws an InvalidOperationException.
A non-nullable value type T is implicitly convertible to the corresponding nullable value type T? .
Lifted operators
The predefined unary and binary operators or any overloaded operators that are supported by a value type T
are also supported by the corresponding nullable value type T? . These operators, also known as lifted
operators, produce null if one or both operands are null ; otherwise, the operator uses the contained values
of its operands to calculate the result. For example:
int? a = 10;
int? b = null;
int? c = 10;
a++; // a is 11
a = a * c; // a is 110
a = a + b; // a is null
NOTE
For the bool? type, the predefined & and | operators don't follow the rules described in this section: the result of
an operator evaluation can be non-null even if one of the operands is null . For more information, see the Nullable
Boolean logical operators section of the Boolean logical operators article.
For the comparison operators < , > , <= , and >= , if one or both operands are null , the result is false ;
otherwise, the contained values of operands are compared. Do not assume that because a particular
comparison (for example, <= ) returns false , the opposite comparison ( > ) returns true . The following
example shows that 10 is
neither greater than or equal to null
nor less than null
int? a = 10;
Console.WriteLine($"{a} >= null is {a >= null}");
Console.WriteLine($"{a} < null is {a < null}");
Console.WriteLine($"{a} == null is {a == null}");
// Output:
// 10 >= null is False
// 10 < null is False
// 10 == null is False
int? b = null;
int? c = null;
Console.WriteLine($"null >= null is {b >= c}");
Console.WriteLine($"null == null is {b == c}");
// Output:
// null >= null is False
// null == null is True
For the equality operator == , if both operands are null , the result is true , if only one of the operands is
null , the result is false ; otherwise, the contained values of operands are compared.
For the inequality operator != , if both operands are null , the result is false , if only one of the operands is
null , the result is true ; otherwise, the contained values of operands are compared.
If there exists a user-defined conversion between two value types, the same conversion can also be used
between the corresponding nullable value types.
int a = 41;
object aBoxed = a;
int? aNullable = (int?)aBoxed;
Console.WriteLine($"Value of aNullable: {aNullable}");
// Output:
// int? is nullable value type
// int is non-nullable value type
As the example shows, you use the typeof operator to create a System.Type instance.
If you want to determine whether an instance is of a nullable value type, don't use the Object.GetType method
to get a Type instance to be tested with the preceding code. When you call the Object.GetType method on an
instance of a nullable value type, the instance is boxed to Object. As boxing of a non-null instance of a nullable
value type is equivalent to boxing of a value of the underlying type, GetType returns a Type instance that
represents the underlying type of a nullable value type:
int? a = 17;
Type typeOfA = a.GetType();
Console.WriteLine(typeOfA.FullName);
// Output:
// System.Int32
Also, don't use the is operator to determine whether an instance is of a nullable value type. As the following
example shows, you cannot distinguish types of a nullable value type instance and its underlying type instance
with the is operator:
int? a = 14;
if (a is int)
{
Console.WriteLine("int? instance is compatible with int");
}
int b = 17;
if (b is int?)
{
Console.WriteLine("int instance is compatible with int?");
}
// Output:
// int? instance is compatible with int
// int instance is compatible with int?
You can use the code presented in the following example to determine whether an instance is of a nullable
value type:
int? a = 14;
Console.WriteLine(IsOfNullableType(a)); // output: True
int b = 17;
Console.WriteLine(IsOfNullableType(b)); // output: False
bool IsOfNullableType<T>(T o)
{
var type = typeof(T);
return Nullable.GetUnderlyingType(type) != null;
}
NOTE
The methods described in this section are not applicable in the case of nullable reference types.
C# language specification
For more information, see the following sections of the C# language specification:
Nullable types
Lifted operators
Implicit nullable conversions
Explicit nullable conversions
Lifted conversion operators
See also
C# reference
What exactly does 'lifted' mean?
System.Nullable<T>
System.Nullable
Nullable.GetUnderlyingType
Nullable reference types
Reference types (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
There are two kinds of types in C#: reference types and value types. Variables of reference types store
references to their data (objects), while variables of value types directly contain their data. With reference
types, two variables can reference the same object; therefore, operations on one variable can affect the object
referenced by the other variable. With value types, each variable has its own copy of the data, and it is not
possible for operations on one variable to affect the other (except in the case of in, ref and out parameter
variables; see in, ref and out parameter modifier).
The following keywords are used to declare reference types:
class
interface
delegate
C# also provides the following built-in reference types:
dynamic
object
string
See also
C# Reference
C# Keywords
Pointer types
Value types
Built-in reference types (C# reference)
3/12/2020 • 6 minutes to read • Edit Online
C# has a number of built-in reference types. They have keywords or operators that are synonyms for a
type in the .NET library.
string a = "hello";
string b = "h";
// Append to contents of 'b'
b += "ello";
Console.WriteLine(a == b);
Console.WriteLine(object.ReferenceEquals(a, b));
This displays "True" and then "False" because the content of the strings are equivalent, but a and b do
not refer to the same string instance.
The + operator concatenates strings:
string b = "h";
b += "ello";
The [] operator can be used for readonly access to individual characters of a string. Valid index values
start at 0 and must be less than the length of the string:
In similar fashion, the [] operator can also be used for iterating over each character in a string:
String literals are of type string and can be written in two forms, quoted and @ -quoted. Quoted string
literals are enclosed in double quotation marks ("):
String literals can contain any character literal. Escape sequences are included. The following example
uses escape sequence \\ for backslash, \u0066 for the letter f, and \n for newline.
NOTE
The escape code \udddd (where dddd is a four-digit number) represents the Unicode character U+ dddd .
Eight-digit Unicode escape codes are also recognized: \Udddddddd .
Verbatim string literals start with @ and are also enclosed in double quotation marks. For example:
The advantage of verbatim strings is that escape sequences are not processed, which makes it easy to
write, for example, a fully qualified Windows file name:
In .NET, System.Action and System.Func types provide generic definitions for many common delegates.
You likely don't need to define new custom delegate types. Instead, you can create instantiations of the
provided generic types.
A delegate is a reference type that can be used to encapsulate a named or an anonymous method.
Delegates are similar to function pointers in C++; however, delegates are type-safe and secure. For
applications of delegates, see Delegates and Generic Delegates. Delegates are the basis for Events. A
delegate can be instantiated by associating it either with a named or anonymous method.
The delegate must be instantiated with a method or lambda expression that has a compatible return
type and input parameters. For more information on the degree of variance that is allowed in the
method signature, see Variance in Delegates. For use with anonymous methods, the delegate and the
code to be associated with it are declared together.
class Program
{
static void Main(string[] args)
{
dynamic dyn = 1;
object obj = 1;
// Rest the mouse pointer over dyn and obj to see their
// types at compile time.
System.Console.WriteLine(dyn.GetType());
System.Console.WriteLine(obj.GetType());
}
}
The WriteLine statements display the run-time types of dyn and obj . At that point, both have the
same type, integer. The following output is produced:
System.Int32
System.Int32
To see the difference between dyn and obj at compile time, add the following two lines between the
declarations and the WriteLine statements in the previous example.
dyn = dyn + 3;
obj = obj + 3;
A compiler error is reported for the attempted addition of an integer and an object in expression
obj + 3 . However, no error is reported for dyn + 3 . The expression that contains dyn is not checked
at compile time because the type of dyn is dynamic .
The following example uses dynamic in several declarations. The Main method also contrasts compile-
time type checking with run-time type checking.
using System;
namespace DynamicExamples
{
class Program
{
static void Main(string[] args)
{
ExampleClass ec = new ExampleClass();
Console.WriteLine(ec.exampleMethod(10));
Console.WriteLine(ec.exampleMethod("value"));
class ExampleClass
{
static dynamic field;
dynamic prop { get; set; }
if (d is int)
{
return local;
}
else
{
return two;
}
}
}
}
// Results:
// Local variable
// 2
// Local variable
See also
C# Reference
C# Keywords
Events
Using Type dynamic
Best Practices for Using Strings
Basic String Operations
Creating New Strings
Type-testing and cast operators
How to safely cast using pattern matching and the as and is operators
Walkthrough: creating and using dynamic objects
System.Object
System.String
System.Dynamic.DynamicObject
class (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
Classes are declared using the keyword class , as shown in the following example:
class TestClass
{
// Methods, properties, fields, events, delegates
// and nested classes go here.
}
Remarks
Only single inheritance is allowed in C#. In other words, a class can inherit implementation from one
base class only. However, a class can implement more than one interface. The following table shows
examples of class inheritance and interface implementation:
IN H ERITA N C E EXA M P L E
Classes that you declare directly within a namespace, not nested within other classes, can be either
public or internal. Classes are internal by default.
Class members, including nested classes, can be public, protected internal, protected, internal, private,
or private protected. Members are private by default.
For more information, see Access Modifiers.
You can declare generic classes that have type parameters. For more information, see Generic Classes.
A class can contain declarations of the following members:
Constructors
Constants
Fields
Finalizers
Methods
Properties
Indexers
Operators
Events
Delegates
Classes
Interfaces
Structure types
Enumeration types
Example
The following example demonstrates declaring class fields, constructors, and methods. It also
demonstrates object instantiation and printing instance data. In this example, two classes are declared.
The first class, Child , contains two private fields ( name and age ), two public constructors and one
public method. The second class, StringTest , is used to contain Main .
class Child
{
private int age;
private string name;
// Default constructor:
public Child()
{
name = "N/A";
}
// Constructor:
public Child(string name, int age)
{
this.name = name;
this.age = age;
}
// Printing method:
public void PrintChild()
{
Console.WriteLine("{0}, {1} years old.", name, age);
}
}
class StringTest
{
static void Main()
{
// Create objects by using the new operator:
Child child1 = new Child("Craig", 11);
Child child2 = new Child("Sally", 10);
// Display results:
Console.Write("Child #1: ");
child1.PrintChild();
Console.Write("Child #2: ");
child2.PrintChild();
Console.Write("Child #3: ");
child3.PrintChild();
}
}
/* Output:
Child #1: Craig, 11 years old.
Child #2: Sally, 10 years old.
Child #3: N/A, 0 years old.
*/
Comments
Notice that in the previous example the private fields ( name and age ) can only be accessed through
the public method of the Child class. For example, you cannot print the child's name, from the Main
method, using a statement like this:
Console.Write(child1.name); // Error
Accessing private members of Child from Main would only be possible if Main were a member of
the class.
Types declared inside a class without an access modifier default to private , so the data members in
this example would still be private if the keyword were removed.
Finally, notice that for the object created using the parameterless constructor ( child3 ), the age field
was initialized to zero by default.
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive
source for C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
Reference Types
interface (C# Reference)
9/3/2020 • 3 minutes to read • Edit Online
An interface defines a contract. Any class or struct that implements that contract must provide an
implementation of the members defined in the interface. Beginning with C# 8.0, an interface may define a
default implementation for members. It may also define static members in order to provide a single
implementation for common functionality.
In the following example, class ImplementationClass must implement a method named SampleMethod that
has no parameters and returns void .
For more information and examples, see Interfaces.
Example
interface ISampleInterface
{
void SampleMethod();
}
An interface can be a member of a namespace or a class. An interface declaration can contain declarations
(signatures without any implementation) of the following members:
Methods
Properties
Indexers
Events
These preceding member declarations typically do not contain a body. Beginning with C# 8.0, an interface
member may declare a body. This is called a default implementation. Members with bodies permit the
interface to provide a "default" implementation for classes and structs that don't provide an overriding
implementation. In addition, beginning with C# 8.0, an interface may include:
Constants
Operators
Static constructor.
Nested types
Static fields, methods, properties, indexers, and events
Member declarations using the explicit interface implementation syntax.
Explicit access modifiers (the default access is public ).
Interfaces may not contain instance state. While static fields are now permitted, instance fields are not
permitted in interfaces. Instance auto-properties are not supported in interfaces, as they would implicitly
declare a hidden field. This rule has a subtle effect on property declarations. In an interface declaration, the
following code does not declare an auto-implemented property as it does in a class or struct . Instead, it
declares a property that doesn't have a default implementation but must be implemented in any type that
implements the interface:
An interface can inherit from one or more base interfaces. When an interface overrides a method
implemented in a base interface, it must use the explicit interface implementation syntax.
When a base type list contains a base class and interfaces, the base class must come first in the list.
A class that implements an interface can explicitly implement members of that interface. An explicitly
implemented member cannot be accessed through a class instance, but only through an instance of the
interface. In addition, default interface members can only be accessed through an instance of the interface.
For more information about explicit interface implementation, see Explicit Interface Implementation.
Example
The following example demonstrates interface implementation. In this example, the interface contains the
property declaration and the class contains the implementation. Any instance of a class that implements
IPoint has integer properties x and y .
interface IPoint
{
// Property signatures:
int X
{
get;
set;
}
int Y
{
get;
set;
}
double Distance
{
get;
}
}
// Property implementation:
public int X { get; set; }
// Property implementation
public double Distance =>
Math.Sqrt(X * X + Y * Y);
class MainClass
{
static void PrintPoint(IPoint p)
{
Console.WriteLine("x={0}, y={1}", p.X, p.Y);
}
C# language specification
For more information, see the Interfaces section of the C# language specification and the feature
specification for Default interface members - C# 8.0
See also
C# Reference
C# Programming Guide
C# Keywords
Reference Types
Interfaces
Using Properties
Using Indexers
Nullable reference types (C# reference)
4/23/2020 • 5 minutes to read • Edit Online
NOTE
This article covers nullable reference types. You can also declare nullable value types.
Nullable reference types are available beginning with C# 8.0, in code that has opted in to a nullable aware context.
Nullable reference types, the null static analysis warnings, and the null-forgiving operator are optional language
features. All are turned off by default. A nullable context is controlled at the project level using build settings, or in
code using pragmas.
In a nullable aware context:
A variable of a reference type T must be initialized with non-null, and may never be assigned a value that may
be null .
A variable of a reference type T? may be initialized with null or assigned null , but is required to be
checked against null before de-referencing.
A variable m of type T? is considered to be non-null when you apply the null-forgiving operator, as in m! .
The distinctions between a non-nullable reference type T and a nullable reference type T? are enforced by the
compiler's interpretation of the preceding rules. A variable of type T and a variable of type T? are represented
by the same .NET type. The following example declares a non-nullable string and a nullable string, and then uses
the null-forgiving operator to assign a value to a non-nullable string:
The variables notNull and nullable are both represented by the String type. Because the non-nullable and
nullable types are both stored as the same type, there are several locations where using a nullable reference type
isn't allowed. In general, a nullable reference type can't be used as a base class or implemented interface. A
nullable reference type can't be used in any object creation or type testing expression. A nullable reference type
can't be the type of a member access expression. The following examples show these constructs:
The following snippet shows where the compiler emits warnings when using this class:
The preceding examples demonstrate the compiler's static analysis to determine the null state of reference
variables. The compiler applies language rules for null checks and assignments to inform its analysis. The compiler
can't make assumptions about the semantics of methods or properties. If you call methods that perform null
checks, the compiler can't know those methods affect a variable's null state. There are a number of attributes you
can add to your APIs to inform the compiler about the semantics of arguments and return values. These attributes
have been applied to many common APIs in the .NET Core libraries. For example, IsNullOrEmpty has been
updated, and the compiler correctly interprets that method as a null check. For more information about the
attributes that apply to null state static analysis, see the article on Nullable attributes.
C# language specification
For more information, see the following proposals for the C# language specification:
Nullable reference types
Draft nullable reference types specification
See also
C# reference
Nullable value types
void (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
You use void as the return type of a method (or a local function) to specify that the method doesn't return a
value.
You can also use void as a referent type to declare a pointer to an unknown type. For more information, see
Pointer types.
You cannot use void as the type of a variable.
See also
C# reference
System.Void
var (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
Beginning in Visual C# 3.0, variables that are declared at method scope can have an implicit "type" var . An
implicitly typed local variable is strongly typed just as if you had declared the type yourself, but the compiler
determines the type. The following two declarations of i are functionally equivalent:
For more information, see Implicitly Typed Local Variables and Type Relationships in LINQ Query Operations.
IMPORTANT
When var is used with nullable reference types enabled, it always implies a nullable reference type even if the
expression type isn't nullable.
Example
The following example shows two query expressions. In the first expression, the use of var is permitted but
is not required, because the type of the query result can be stated explicitly as an IEnumerable<string> .
However, in the second expression, var allows the result to be a collection of anonymous types, and the
name of that type is not accessible except to the compiler itself. Use of var eliminates the requirement to
create a new class for the result. Note that in Example #2, the foreach iteration variable item must also be
implicitly typed.
C # T Y P E K EY W O RD . N ET T Y P E
bool System.Boolean
byte System.Byte
sbyte System.SByte
char System.Char
decimal System.Decimal
double System.Double
float System.Single
int System.Int32
uint System.UInt32
long System.Int64
ulong System.UInt64
short System.Int16
ushort System.UInt16
C # T Y P E K EY W O RD . N ET T Y P E
object System.Object
string System.String
dynamic System.Object
In the preceding tables, each C# type keyword from the left column is an alias for the corresponding .NET type.
They are interchangeable. For example, the following declarations declare variables of the same type:
int a = 123;
System.Int32 b = 123;
The void keyword represents the absence of a type. You use it as the return type of a method that doesn't return
a value.
See also
C# reference
Default values of C# types
Unmanaged types (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
using System;
A generic struct may be the source of both unmanaged and not unmanaged constructed types. The preceding
example defines a generic struct Coords<T> and presents the examples of unmanaged constructed types. The
example of not an unmanaged type is Coords<object> . It's not unmanaged because it has the fields of the
object type, which is not unmanaged. If you want all constructed types to be unmanaged types, use the
unmanaged constraint in the definition of a generic struct:
See also
C# reference
Pointer types
Memory and span-related types
sizeof operator
stackalloc
Default values of C# types (C# reference)
3/18/2020 • 2 minutes to read • Edit Online
bool false
Any nullable value type An instance for which the HasValue property is false and
the Value property is undefined. That default value is also
known as the null value of a nullable value type.
Use the default operator to produce the default value of a type, as the following example shows:
int a = default(int);
Beginning with C# 7.1, you can use the default literal to initialize a variable with the default value of its type:
int a = default;
For a value type, the implicit parameterless constructor also produces the default value of the type, as the
following example shows:
At run time, if the System.Type instance represents a value type, you can use the Activator.CreateInstance(Type)
method to invoke the parameterless constructor to obtain the default value of the type.
C# language specification
For more information, see the following sections of the C# language specification:
Default values
Default constructors
See also
C# reference
Constructors
C# Keywords
9/3/2020 • 2 minutes to read • Edit Online
Keywords are predefined, reserved identifiers that have special meanings to the compiler. They cannot
be used as identifiers in your program unless they include @ as a prefix. For example, @if is a valid
identifier, but if is not because if is a keyword.
The first table in this topic lists keywords that are reserved identifiers in any part of a C# program. The
second table in this topic lists the contextual keywords in C#. Contextual keywords have special
meaning only in a limited program context and can be used as identifiers outside that context.
Generally, as new keywords are added to the C# language, they are added as contextual keywords in
order to avoid breaking programs written in earlier versions.
while
Contextual keywords
A contextual keyword is used to provide a specific meaning in the code, but it is not a reserved word in
C#. Some contextual keywords, such as partial and where , have special meanings in two or more
contexts.
async await by
See also
C# reference
Access Modifiers (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
Access modifiers are keywords used to specify the declared accessibility of a member or a type. This section
introduces the four access modifiers:
public
protected
internal
private
The following six accessibility levels can be specified using the access modifiers:
public : Access is not restricted.
protected : Access is limited to the containing class or types derived from the containing class.
internal : Access is limited to the current assembly.
protected internal : Access is limited to the current assembly or types derived from the containing class.
private : Access is limited to the containing type.
private protected : Access is limited to the containing class or types derived from the containing class
within the current assembly.
This section also introduces the following:
Accessibility Levels: Using the four access modifiers to declare six levels of accessibility.
Accessibility Domain: Specifies where, in the program sections, a member can be referenced.
Restrictions on Using Accessibility Levels: A summary of the restrictions on using declared accessibility
levels.
See also
C# Reference
C# Programming Guide
C# Keywords
Access Modifiers
Access Keywords
Modifiers
Accessibility Levels (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
Use the access modifiers, public , protected , internal , or private , to specify one of the following declared
accessibility levels for members.
private protected Access is limited to the containing class or types derived from
the containing class within the current assembly. Available
since C# 7.2.
Only one access modifier is allowed for a member or type, except when you use the protected internal or
private protected combinations.
Access modifiers are not allowed on namespaces. Namespaces have no access restrictions.
Depending on the context in which a member declaration occurs, only certain declared accessibilities are
permitted. If no access modifier is specified in a member declaration, a default accessibility is used.
Top-level types, which are not nested in other types, can only have internal or public accessibility. The default
accessibility for these types is internal .
Nested types, which are members of other types, can have declared accessibilities as indicated in the following
table.
protected
internal
private
protected internal
private protected
internal
private
The accessibility of a nested type depends on its accessibility domain, which is determined by both the declared
accessibility of the member and the accessibility domain of the immediately containing type. However, the
accessibility domain of a nested type cannot exceed that of the containing type.
C# Language Specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
Access Modifiers
Accessibility Domain
Restrictions on Using Accessibility Levels
Access Modifiers
public
private
protected
internal
Accessibility Domain (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The accessibility domain of a member specifies in which program sections a member can be referenced. If the
member is nested within another type, its accessibility domain is determined by both the accessibility level of the
member and the accessibility domain of the immediately containing type.
The accessibility domain of a top-level type is at least the program text of the project that it is declared in. That is,
the domain includes all of the source files of this project. The accessibility domain of a nested type is at least the
program text of the type in which it is declared. That is, the domain is the type body, which includes all nested
types. The accessibility domain of a nested type never exceeds that of the containing type. These concepts are
demonstrated in the following example.
Example
This example contains a top-level type, T1 , and two nested classes, M1 and M2 . The classes contain fields that
have different declared accessibilities. In the Main method, a comment follows each statement to indicate the
accessibility domain of each member. Notice that the statements that try to reference the inaccessible members
are commented out. If you want to see the compiler errors caused by referencing an inaccessible member, remove
the comments one at a time.
public class T1
{
public static int publicInt;
internal static int internalInt;
private static int privateInt = 0;
static T1()
{
// T1 can access public or internal members
// in a public or private (or internal) nested class.
M1.publicInt = 1;
M1.internalInt = 2;
M2.publicInt = 3;
M2.internalInt = 4;
public class M1
{
public static int publicInt;
internal static int internalInt;
private static int privateInt = 0;
}
private class M2
{
public static int publicInt = 0;
internal static int internalInt = 0;
private static int privateInt = 0;
}
}
class MainClass
{
{
static void Main()
{
// Access is unlimited.
T1.publicInt = 1;
// Access is unlimited.
T1.M1.publicInt = 1;
C# Language Specification
For more information, see the C# Language Specification. The language specification is the definitive source for C#
syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
Access Modifiers
Accessibility Levels
Restrictions on Using Accessibility Levels
Access Modifiers
public
private
protected
internal
Restrictions on using accessibility levels (C#
Reference)
9/3/2020 • 2 minutes to read • Edit Online
When you specify a type in a declaration, check whether the accessibility level of the type is dependent on the
accessibility level of a member or of another type. For example, the direct base class must be at least as accessible
as the derived class. The following declarations cause a compiler error because the base class BaseClass is less
accessible than MyClass :
C O N T EXT REM A RK S
Delegates The return type and parameter types of a delegate type must
be at least as accessible as the delegate type itself.
using System;
// A delegate:
delegate int MyDelegate();
class B
{
// A private method:
static int MyPrivateMethod()
{
return 0;
}
}
public class A
{
// Error: The type B is less accessible than the field A.myField.
public B myField = new B();
public B MyMethod()
{
// Error: The type B is less accessible
// than the method A.MyMethod.
return new B();
}
See also
C# Reference
C# Programming Guide
C# Keywords
Access Modifiers
Accessibility Domain
Accessibility Levels
Access Modifiers
public
private
protected
internal
internal (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The internal keyword is an access modifier for types and type members.
This page covers internal access. The internal keyword is also part of the protected internal access
modifier.
Internal types or members are accessible only within files in the same assembly, as in this example:
For a comparison of internal with the other access modifiers, see Accessibility Levels and Access Modifiers.
For more information about assemblies, see Assemblies in .NET.
A common use of internal access is in component-based development because it enables a group of
components to cooperate in a private manner without being exposed to the rest of the application code. For
example, a framework for building graphical user interfaces could provide Control and Form classes that
cooperate by using members with internal access. Since these members are internal, they are not exposed to
code that is using the framework.
It is an error to reference a type or a member with internal access outside the assembly within which it was
defined.
Example
This example contains two files, Assembly1.cs and Assembly1_a.cs . The first file contains an internal base
class, BaseClass . In the second file, an attempt to instantiate BaseClass will produce an error.
// Assembly1.cs
// Compile with: /target:library
internal class BaseClass
{
public static int intM = 0;
}
// Assembly1_a.cs
// Compile with: /reference:Assembly1.dll
class TestAccess
{
static void Main()
{
var myBase = new BaseClass(); // CS0122
}
}
Example
In this example, use the same files you used in example 1, and change the accessibility level of BaseClass to
public . Also change the accessibility level of the member intM to internal . In this case, you can instantiate
the class, but you cannot access the internal member.
// Assembly2.cs
// Compile with: /target:library
public class BaseClass
{
internal static int intM = 0;
}
// Assembly2_a.cs
// Compile with: /reference:Assembly2.dll
public class TestAccess
{
static void Main()
{
var myBase = new BaseClass(); // Ok.
BaseClass.intM = 444; // CS0117
}
}
C# Language Specification
For more information, see Declared accessibility in the C# Language Specification. The language specification
is the definitive source for C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
Access Modifiers
Accessibility Levels
Modifiers
public
private
protected
private (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
This page covers private access. The private keyword is also part of the private protected access
modifier.
Private access is the least permissive access level. Private members are accessible only within the body of
the class or the struct in which they are declared, as in this example:
class Employee
{
private int i;
double d; // private access by default
}
Nested types in the same body can also access those private members.
It is a compile-time error to reference a private member outside the class or the struct in which it is
declared.
For a comparison of private with the other access modifiers, see Accessibility Levels and Access Modifiers.
Example
In this example, the Employee class contains two private data members, name and salary . As private
members, they cannot be accessed except by member methods. Public methods named GetName and
Salary are added to allow controlled access to the private members. The name member is accessed by
way of a public method, and the salary member is accessed by way of a public read-only property. (See
Properties for more information.)
class Employee2
{
private string name = "FirstName, LastName";
private double salary = 100.0;
class PrivateTest
{
static void Main()
{
var e = new Employee2();
C# language specification
For more information, see Declared accessibility in the C# Language Specification. The language
specification is the definitive source for C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
Access Modifiers
Accessibility Levels
Modifiers
public
protected
internal
protected (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
This page covers protected access. The protected keyword is also part of the protected internal and
private protected access modifiers.
A protected member is accessible within its class and by derived class instances.
For a comparison of protected with the other access modifiers, see Accessibility Levels.
Example
A protected member of a base class is accessible in a derived class only if the access occurs through the
derived class type. For example, consider the following code segment:
class A
{
protected int x = 123;
}
class B : A
{
static void Main()
{
var a = new A();
var b = new B();
The statement a.x = 10 generates an error because it is made within the static method Main, and not an
instance of class B.
Struct members cannot be protected because the struct cannot be inherited.
Example
In this example, the class DerivedPoint is derived from Point . Therefore, you can access the protected
members of the base class directly from the derived class.
class Point
{
protected int x;
protected int y;
}
If you change the access levels of x and y to private, the compiler will issue the error messages:
'Point.y' is inaccessible due to its protection level.
C# language specification
For more information, see Declared accessibility in the C# Language Specification. The language specification
is the definitive source for C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
Access Modifiers
Accessibility Levels
Modifiers
public
private
internal
Security concerns for internal virtual keywords
public (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The public keyword is an access modifier for types and type members. Public access is the most
permissive access level. There are no restrictions on accessing public members, as in this example:
class SampleClass
{
public int x; // No access restrictions.
}
Example
In the following example, two classes are declared, PointTest and MainClass . The public members x and
y of PointTest are accessed directly from MainClass .
class PointTest
{
public int x;
public int y;
}
class MainClass4
{
static void Main()
{
var p = new PointTest();
// Direct access to public members.
p.x = 10;
p.y = 15;
Console.WriteLine($"x = {p.x}, y = {p.y}");
}
}
// Output: x = 10, y = 15
If you change the public access level to private or protected, you will get the error message:
'PointTest.y' is inaccessible due to its protection level.
C# language specification
For more information, see Declared accessibility in the C# Language Specification. The language
specification is the definitive source for C# syntax and usage.
See also
C# Reference
C# Programming Guide
Access Modifiers
C# Keywords
Access Modifiers
Accessibility Levels
Modifiers
private
protected
internal
protected internal (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The protected internal keyword combination is a member access modifier. A protected internal member is
accessible from the current assembly or from types that are derived from the containing class. For a
comparison of protected internal with the other access modifiers, see Accessibility Levels.
Example
A protected internal member of a base class is accessible from any type within its containing assembly. It is also
accessible in a derived class located in another assembly only if the access occurs through a variable of the
derived class type. For example, consider the following code segment:
// Assembly1.cs
// Compile with: /target:library
public class BaseClass
{
protected internal int myValue = 0;
}
class TestAccess
{
void Access()
{
var baseObject = new BaseClass();
baseObject.myValue = 5;
}
}
// Assembly2.cs
// Compile with: /reference:Assembly1.dll
class DerivedClass : BaseClass
{
static void Main()
{
var baseObject = new BaseClass();
var derivedObject = new DerivedClass();
This example contains two files, Assembly1.cs and Assembly2.cs . The first file contains a public base class,
BaseClass , and another class, TestAccess . BaseClass owns a protected internal member, myValue , which is
accessed by the TestAccess type. In the second file, an attempt to access myValue through an instance of
BaseClass will produce an error, while an access to this member through an instance of a derived class,
DerivedClass will succeed.
Struct members cannot be protected internal because the struct cannot be inherited.
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
Access Modifiers
Accessibility Levels
Modifiers
public
private
internal
Security concerns for internal virtual keywords
private protected (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The private protected keyword combination is a member access modifier. A private protected member is
accessible by types derived from the containing class, but only within its containing assembly. For a comparison
of private protected with the other access modifiers, see Accessibility Levels.
NOTE
The private protected access modifier is valid in C# version 7.2 and later.
Example
A private protected member of a base class is accessible from derived types in its containing assembly only if
the static type of the variable is the derived class type. For example, consider the following code segment:
// Assembly2.cs
// Compile with: /reference:Assembly1.dll
class DerivedClass2 : BaseClass
{
void Access()
{
// Error CS0122, because myValue can only be
// accessed by types in Assembly1
// myValue = 10;
}
}
This example contains two files, Assembly1.cs and Assembly2.cs . The first file contains a public base class,
BaseClass , and a type derived from it, DerivedClass1 . BaseClass owns a private protected member, myValue ,
which DerivedClass1 tries to access in two ways. The first attempt to access myValue through an instance of
BaseClass will produce an error. However, the attempt to use it as an inherited member in DerivedClass1 will
succeed.
In the second file, an attempt to access myValue as an inherited member of DerivedClass2 will produce an
error, as it is only accessible by derived types in Assembly1.
If Assembly1.cs contains an InternalsVisibleToAttribute that names Assembly2 , the derived class DerivedClass1
will have access to private protected members declared in BaseClass . InternalsVisibleTo makes
private protected members visible to derived classes in other assemblies.
Struct members cannot be private protected because the struct cannot be inherited.
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
Access Modifiers
Accessibility Levels
Modifiers
public
private
internal
Security concerns for internal virtual keywords
abstract (C# Reference)
9/3/2020 • 3 minutes to read • Edit Online
The abstract modifier indicates that the thing being modified has a missing or incomplete implementation.
The abstract modifier can be used with classes, methods, properties, indexers, and events. Use the abstract
modifier in a class declaration to indicate that a class is intended only to be a base class of other classes, not
instantiated on its own. Members marked as abstract must be implemented by non-abstract classes that
derive from the abstract class.
Example
In this example, the class Square must provide an implementation of GetArea because it derives from
Shape :
interface I
{
void M();
}
abstract class C : I
{
public abstract void M();
}
Example
In this example, the class DerivedClass is derived from an abstract class BaseClass . The abstract class
contains an abstract method, AbstractMethod , and two abstract properties, X and Y .
abstract class BaseClass // Abstract class
{
protected int _x = 100;
protected int _y = 150;
public abstract void AbstractMethod(); // Abstract method
public abstract int X { get; }
public abstract int Y { get; }
}
In the preceding example, if you attempt to instantiate the abstract class by using a statement like this:
You will get an error saying that the compiler cannot create an instance of the abstract class 'BaseClass'.
C# Language Specification
For more information, see the C# Language Specification. The language specification is the definitive source
for C# syntax and usage.
See also
C# Reference
C# Programming Guide
Modifiers
virtual
override
C# Keywords
async (C# Reference)
9/3/2020 • 4 minutes to read • Edit Online
Use the async modifier to specify that a method, lambda expression, or anonymous method is asynchronous.
If you use this modifier on a method or expression, it's referred to as an async method. The following example
defines an async method named ExampleMethodAsync :
If you're new to asynchronous programming or do not understand how an async method uses the await
operator to do potentially long-running work without blocking the caller's thread, read the introduction in
Asynchronous programming with async and await. The following code is found inside an async method and
calls the HttpClient.GetStringAsync method:
An async method runs synchronously until it reaches its first await expression, at which point the method is
suspended until the awaited task is complete. In the meantime, control returns to the caller of the method, as
the example in the next section shows.
If the method that the async keyword modifies doesn't contain an await expression or statement, the
method executes synchronously. A compiler warning alerts you to any async methods that don't contain
await statements, because that situation might indicate an error. See Compiler Warning (level 1) CS4014.
The async keyword is contextual in that it's a keyword only when it modifies a method, a lambda expression,
or an anonymous method. In all other contexts, it's interpreted as an identifier.
Example
The following example shows the structure and flow of control between an async event handler,
StartButton_Click , and an async method, ExampleMethodAsync . The result from the async method is the
number of characters of a web page. The code is suitable for a Windows Presentation Foundation (WPF) app
or Windows Store app that you create in Visual Studio; see the code comments for setting up the app.
You can run this code in Visual Studio as a Windows Presentation Foundation (WPF) app or a Windows Store
app. You need a Button control named StartButton and a Textbox control named ResultsTextBox . Remember
to set the names and handler so that you have something like this:
try
{
int length = await ExampleMethodAsync();
// Note that you could put "await ExampleMethodAsync()" in the next line where
// "length" is, but due to when '+=' fetches the value of ResultsTextBox, you
// would not see the global side effect of ExampleMethodAsync setting the text.
ResultsTextBox.Text += String.Format("Length: {0:N0}\n", length);
}
catch (Exception)
{
// Process the exception if one occurs.
}
}
IMPORTANT
For more information about tasks and the code that executes while waiting for a task, see Asynchronous programming
with async and await. For a full console example that uses similar elements, see Process asynchronous tasks as they
complete (C#).
Return Types
An async method can have the following return types:
Task
Task<TResult>
void. async void methods are generally discouraged for code other than event handlers because callers
cannot await those methods and must implement a different mechanism to report successful completion
or error conditions.
Starting with C# 7.0, any type that has an accessible GetAwaiter method. The
System.Threading.Tasks.ValueTask<TResult> type is one such implementation. It is available by adding the
NuGet package System.Threading.Tasks.Extensions .
The async method can't declare any in, ref or out parameters, nor can it have a reference return value, but it
can call methods that have such parameters.
You specify Task<TResult> as the return type of an async method if the return statement of the method
specifies an operand of type TResult . You use Task if no meaningful value is returned when the method is
completed. That is, a call to the method returns a Task , but when the Task is completed, any await
expression that's awaiting the Task evaluates to void .
You use the void return type primarily to define event handlers, which require that return type. The caller of a
void -returning async method can't await it and can't catch exceptions that the method throws.
Starting with C# 7.0, you return another type, typically a value type, that has a GetAwaiter method to minimize
memory allocations in performance-critical sections of code.
For more information and examples, see Async Return Types.
See also
AsyncStateMachineAttribute
await
Asynchronous programming with async and await
Process asynchronous tasks as they complete
const (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
You use the const keyword to declare a constant field or a constant local. Constant fields and locals aren't
variables and may not be modified. Constants can be numbers, Boolean values, strings, or a null reference. Don’t
create a constant to represent information that you expect to change at any time. For example, don’t use a
constant field to store the price of a service, a product version number, or the brand name of a company. These
values can change over time, and because compilers propagate constants, other code compiled with your
libraries will have to be recompiled to see the changes. See also the readonly keyword. For example:
const int X = 0;
public const double GravitationalConstant = 6.673e-11;
private const string ProductName = "Visual C#";
Remarks
The type of a constant declaration specifies the type of the members that the declaration introduces. The
initializer of a constant local or a constant field must be a constant expression that can be implicitly converted to
the target type.
A constant expression is an expression that can be fully evaluated at compile time. Therefore, the only possible
values for constants of reference types are string and a null reference.
The constant declaration can declare multiple constants, such as:
NOTE
The readonly keyword differs from the const keyword. A const field can only be initialized at the declaration of the field.
A readonly field can be initialized either at the declaration or in a constructor. Therefore, readonly fields can have
different values depending on the constructor used. Also, although a const field is a compile-time constant, the
readonly field can be used for run-time constants, as in this line:
public static readonly uint l1 = (uint)DateTime.Now.Ticks;
Example
public class ConstTest
{
class SampleClass
{
public int x;
public int y;
public const int C1 = 5;
public const int C2 = C1 + 5;
Example
This example demonstrates how to use constants as local variables.
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
Modifiers
readonly
event (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
Example
The following example shows how to declare and raise an event that uses EventHandler as the underlying
delegate type. For the complete code example that also shows how to use the generic
EventHandler<TEventArgs> delegate type and how to subscribe to an event and create an event handler method,
see How to publish events that conform to .NET Framework Guidelines.
Events are a special kind of multicast delegate that can only be invoked from within the class or struct where they
are declared (the publisher class). If other classes or structs subscribe to the event, their event handler methods
will be called when the publisher class raises the event. For more information and code examples, see Events and
Delegates.
Events can be marked as public, private, protected, internal, protected internal, or private protected. These access
modifiers define how users of the class can access the event. For more information, see Access Modifiers.
K EY W O RD DESC RIP T IO N F O R M O RE IN F O RM AT IO N
static Makes the event available to callers at Static Classes and Static Class Members
any time, even if no instance of the
class exists.
K EY W O RD DESC RIP T IO N F O R M O RE IN F O RM AT IO N
An event may be declared as a static event by using the static keyword. This makes the event available to callers
at any time, even if no instance of the class exists. For more information, see Static Classes and Static Class
Members.
An event can be marked as a virtual event by using the virtual keyword. This enables derived classes to override
the event behavior by using the override keyword. For more information, see Inheritance. An event overriding a
virtual event can also be sealed, which specifies that for derived classes it is no longer virtual. Lastly, an event can
be declared abstract, which means that the compiler will not generate the add and remove event accessor
blocks. Therefore derived classes must provide their own implementation.
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
add
remove
Modifiers
How to combine delegates (Multicast Delegates)
extern (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The extern modifier is used to declare a method that is implemented externally. A common use of the extern
modifier is with the DllImport attribute when you are using Interop services to call into unmanaged code. In this
case, the method must also be declared as static , as shown in the following example:
[DllImport("avifil32.dll")]
private static extern void AVIFileInit();
The extern keyword can also define an external assembly alias, which makes it possible to reference different
versions of the same component from within a single assembly. For more information, see extern alias.
It is an error to use the abstract and extern modifiers together to modify the same member. Using the extern
modifier means that the method is implemented outside the C# code, whereas using the abstract modifier
means that the method implementation is not provided in the class.
The extern keyword has more limited uses in C# than in C++. To compare the C# keyword with the C++ keyword,
see Using extern to Specify Linkage in the C++ Language Reference.
Example 1
In this example, the program receives a string from the user and displays it inside a message box. The program
uses the MessageBox method imported from the User32.dll library.
//using System.Runtime.InteropServices;
class ExternTest
{
[DllImport("User32.dll", CharSet=CharSet.Unicode)]
public static extern int MessageBox(IntPtr h, string m, string c, int type);
Example 2
This example illustrates a C# program that calls into a C library (a native DLL).
1. Create the following C file and name it cmdll.c :
// cmdll.c
// Compile with: -LD
int __declspec(dllexport) SampleMethod(int i)
{
return i*10;
}
2. Open a Visual Studio x64 (or x32) Native Tools Command Prompt window from the Visual Studio
installation directory and compile the cmdll.c file by typing cl -LD cmdll.c at the command prompt.
3. In the same directory, create the following C# file and name it cm.cs :
// cm.cs
using System;
using System.Runtime.InteropServices;
public class MainClass
{
[DllImport("Cmdll.dll")]
public static extern int SampleMethod(int x);
4. Open a Visual Studio x64 (or x32) Native Tools Command Prompt window from the Visual Studio
installation directory and compile the cm.cs file by typing:
csc cm.cs (for the x64 command prompt) —or— csc -platform:x86 cm.cs (for the x32 command
prompt)
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for C#
syntax and usage.
See also
System.Runtime.InteropServices.DllImportAttribute
C# Reference
C# Programming Guide
C# Keywords
Modifiers
in (Generic Modifier) (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
For generic type parameters, the in keyword specifies that the type parameter is contravariant. You can use the
in keyword in generic interfaces and delegates.
Contravariance enables you to use a less derived type than that specified by the generic parameter. This allows for
implicit conversion of classes that implement contravariant interfaces and implicit conversion of delegate types.
Covariance and contravariance in generic type parameters are supported for reference types, but they are not
supported for value types.
A type can be declared contravariant in a generic interface or delegate only if it defines the type of a method's
parameters and not of a method's return type. In , ref , and out parameters must be invariant, meaning they are
neither covariant or contravariant.
An interface that has a contravariant type parameter allows its methods to accept arguments of less derived types
than those specified by the interface type parameter. For example, in the IComparer<T> interface, type T is
contravariant, you can assign an object of the IComparer<Person> type to an object of the IComparer<Employee> type
without using any special conversion methods if Employee inherits Person .
A contravariant delegate can be assigned another delegate of the same type, but with a less derived generic type
parameter.
For more information, see Covariance and Contravariance.
// Contravariant interface.
interface IContravariant<in A> { }
class Program
{
static void Test()
{
IContravariant<Object> iobj = new Sample<Object>();
IContravariant<String> istr = new Sample<String>();
// Contravariant delegate.
public delegate void DContravariant<in A>(A argument);
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for C#
syntax and usage.
See also
out
Covariance and Contravariance
Modifiers
new modifier (C# Reference)
9/3/2020 • 3 minutes to read • Edit Online
When used as a declaration modifier, the new keyword explicitly hides a member that is inherited from a base
class. When you hide an inherited member, the derived version of the member replaces the base class version.
Although you can hide members without using the new modifier, you get a compiler warning. If you use new
to explicitly hide a member, it suppresses this warning.
You can also use the new keyword to create an instance of a type or as a generic type constraint.
To hide an inherited member, declare it in the derived class by using the same member name, and modify it with
the new keyword. For example:
In this example, BaseC.Invoke is hidden by DerivedC.Invoke . The field x is not affected because it is not hidden
by a similar name.
Name hiding through inheritance takes one of the following forms:
Generally, a constant, field, property, or type that is introduced in a class or struct hides all base class
members that share its name. There are special cases. For example, if you declare a new field with name
N to have a type that is not invocable, and a base type declares N to be a method, the new field does
not hide the base declaration in invocation syntax. For more information, see the Member lookup section
of the C# language specification.
A method introduced in a class or struct hides properties, fields, and types that share that name in the
base class. It also hides all base class methods that have the same signature.
An indexer introduced in a class or struct hides all base class indexers that have the same signature.
It is an error to use both new and override on the same member, because the two modifiers have mutually
exclusive meanings. The new modifier creates a new member with the same name and causes the original
member to become hidden. The override modifier extends the implementation for an inherited member.
Using the new modifier in a declaration that does not hide an inherited member generates a warning.
Example
In this example, a base class, BaseC , and a derived class, DerivedC , use the same field name x , which hides the
value of the inherited field. The example demonstrates the use of the new modifier. It also demonstrates how to
access the hidden members of the base class by using their fully qualified names.
public class BaseC
{
public static int x = 55;
public static int y = 22;
}
Example
In this example, a nested class hides a class that has the same name in the base class. The example demonstrates
how to use the new modifier to eliminate the warning message and how to access the hidden class members
by using their fully qualified names.
public class BaseC
{
public class NestedC
{
public int x = 200;
public int y;
}
}
Console.WriteLine(c1.x);
Console.WriteLine(c2.x);
}
}
/*
Output:
100
200
*/
If you remove the new modifier, the program will still compile and run, but you will get the following warning:
The keyword new is required on 'MyDerivedC.x' because it hides inherited member 'MyBaseC.x'.
C# language specification
For more information, see The new modifier section of the C# language specification.
See also
C# Reference
C# Programming Guide
C# Keywords
Modifiers
Versioning with the Override and New Keywords
Knowing When to Use Override and New Keywords
out (generic modifier) (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
For generic type parameters, the out keyword specifies that the type parameter is covariant. You can use the out
keyword in generic interfaces and delegates.
Covariance enables you to use a more derived type than that specified by the generic parameter. This allows for
implicit conversion of classes that implement covariant interfaces and implicit conversion of delegate types.
Covariance and contravariance are supported for reference types, but they are not supported for value types.
An interface that has a covariant type parameter enables its methods to return more derived types than those
specified by the type parameter. For example, because in .NET Framework 4, in IEnumerable<T>, type T is
covariant, you can assign an object of the IEnumerable(Of String) type to an object of the IEnumerable(Of Object)
type without using any special conversion methods.
A covariant delegate can be assigned another delegate of the same type, but with a more derived generic type
parameter.
For more information, see Covariance and Contravariance.
// Covariant interface.
interface ICovariant<out R> { }
class Program
{
static void Test()
{
ICovariant<Object> iobj = new Sample<Object>();
ICovariant<String> istr = new Sample<String>();
In a generic interface, a type parameter can be declared covariant if it satisfies the following conditions:
The type parameter is used only as a return type of interface methods and not used as a type of method
arguments.
NOTE
There is one exception to this rule. If in a covariant interface you have a contravariant generic delegate as a method
parameter, you can use the covariant type as a generic type parameter for this delegate. For more information about
covariant and contravariant generic delegates, see Variance in Delegates and Using Variance for Func and Action
Generic Delegates.
The type parameter is not used as a generic constraint for the interface methods.
// Covariant delegate.
public delegate R DCovariant<out R>();
In a generic delegate, a type can be declared covariant if it is used only as a method return type and not used for
method arguments.
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for C#
syntax and usage.
See also
Variance in Generic Interfaces
in
Modifiers
override (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The override modifier is required to extend or modify the abstract or virtual implementation of an inherited
method, property, indexer, or event.
Example
In this example, the Square class must provide an overridden implementation of GetArea because GetArea
is inherited from the abstract Shape class:
An override method provides a new implementation of a member that is inherited from a base class. The
method that is overridden by an override declaration is known as the overridden base method. The
overridden base method must have the same signature as the override method. For information about
inheritance, see Inheritance.
You cannot override a non-virtual or static method. The overridden base method must be virtual ,
abstract , or override .
An override declaration cannot change the accessibility of the virtual method. Both the override method
and the virtual method must have the same access level modifier.
You cannot use the new , static , or virtual modifiers to modify an override method.
An overriding property declaration must specify exactly the same access modifier, type, and name as the
inherited property, and the overridden property must be virtual , abstract , or override .
For more information about how to use the override keyword, see Versioning with the Override and New
Keywords and Knowing when to use Override and New Keywords.
Example
This example defines a base class named Employee , and a derived class named SalesEmployee . The
SalesEmployee class includes an extra field, salesbonus , and overrides the method CalculatePay in order to
take it into account.
class TestOverride
{
public class Employee
{
public string name;
See also
C# Reference
C# Programming Guide
Inheritance
C# Keywords
Modifiers
abstract
virtual
new (modifier)
Polymorphism
readonly (C# Reference)
9/3/2020 • 3 minutes to read • Edit Online
WARNING
An externally visible type that contains an externally visible read-only field that is a mutable reference type may be
a security vulnerability and may trigger warning CA2104 : "Do not declare read only mutable reference types."
In a readonly struct type definition, readonly indicates that the structure type is immutable. For more
information, see the readonly struct section of the Structure types article.
In an instance member declaration within a structure type, readonly indicates that an instance member
doesn't modify the state of the structure. For more information, see the readonly instance members
section of the Structure types article.
In a ref readonly method return, the readonly modifier indicates that method returns a reference and
writes aren't allowed to that reference.
The readonly struct and ref readonly contexts were added in C# 7.2. readonly struct members were added in
C# 8.0
You can assign a value to a readonly field only in the following contexts:
When the variable is initialized in the declaration, for example:
In an instance constructor of the class that contains the instance field declaration.
In the static constructor of the class that contains the static field declaration.
These constructor contexts are also the only contexts in which it's valid to pass a readonly field as an out or ref
parameter.
NOTE
The readonly keyword is different from the const keyword. A const field can only be initialized at the declaration of the
field. A readonly field can be assigned multiple times in the field declaration and in any constructor. Therefore, readonly
fields can have different values depending on the constructor used. Also, while a const field is a compile-time constant,
the readonly field can be used for run-time constants as in the following example:
public SamplePoint()
{
// Initialize a readonly instance field
z = 24;
}
In the preceding example, if you use a statement like the following example:
The type returned doesn't need to be a readonly struct . Any type that can be returned by ref can be returned
by ref readonly .
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
You can also see the language specification proposals:
readonly ref and readonly struct
readonly struct members
See also
C# Reference
C# Programming Guide
C# Keywords
Modifiers
const
Fields
sealed (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
When applied to a class, the sealed modifier prevents other classes from inheriting from it. In the following
example, class B inherits from class A , but no class can inherit from class B .
class A {}
sealed class B : A {}
You can also use the sealed modifier on a method or property that overrides a virtual method or property in
a base class. This enables you to allow classes to derive from your class and prevent them from overriding
specific virtual methods or properties.
Example
In the following example, Z inherits from Y but Z cannot override the virtual function F that is declared
in X and sealed in Y .
class X
{
protected virtual void F() { Console.WriteLine("X.F"); }
protected virtual void F2() { Console.WriteLine("X.F2"); }
}
class Y : X
{
sealed protected override void F() { Console.WriteLine("Y.F"); }
protected override void F2() { Console.WriteLine("Y.F2"); }
}
class Z : Y
{
// Attempting to override F causes compiler error CS0239.
// protected override void F() { Console.WriteLine("Z.F"); }
// Overriding F2 is allowed.
protected override void F2() { Console.WriteLine("Z.F2"); }
}
When you define new methods or properties in a class, you can prevent deriving classes from overriding
them by not declaring them as virtual.
It is an error to use the abstract modifier with a sealed class, because an abstract class must be inherited by a
class that provides an implementation of the abstract methods or properties.
When applied to a method or property, the sealed modifier must always be used with override.
Because structs are implicitly sealed, they cannot be inherited.
For more information, see Inheritance.
For more examples, see Abstract and Sealed Classes and Class Members.
Example
sealed class SealedClass
{
public int x;
public int y;
}
class SealedTest2
{
static void Main()
{
var sc = new SealedClass();
sc.x = 110;
sc.y = 150;
Console.WriteLine($"x = {sc.x}, y = {sc.y}");
}
}
// Output: x = 110, y = 150
In the previous example, you might try to inherit from the sealed class by using the following statement:
class MyDerivedC: SealedClass {} // Error
Remarks
To determine whether to seal a class, method, or property, you should generally consider the following two
points:
The potential benefits that deriving classes might gain through the ability to customize your class.
The potential that deriving classes could modify your classes in such a way that they would no longer
work correctly or as expected.
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source
for C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
Static Classes and Static Class Members
Abstract and Sealed Classes and Class Members
Access Modifiers
Modifiers
override
virtual
static (C# Reference)
9/3/2020 • 3 minutes to read • Edit Online
This page covers the static modifier keyword. The static keyword is also part of the using static
directive.
Use the static modifier to declare a static member, which belongs to the type itself rather than to a specific
object. The static modifier can be used to declare static classes. In classes, interfaces, and structs, you
may add the static modifier to fields, methods, properties, operators, events, and constructors. The
static modifier can't be used with indexers or finalizers. For more information, see Static Classes and Static
Class Members.
A constant or type declaration is implicitly a static member. A static member can't be referenced
through an instance. Instead, it's referenced through the type name. For example, consider the following
class:
To refer to the static member x , use the fully qualified name, MyBaseC.MyStruct.x , unless the member is
accessible from the same scope:
Console.WriteLine(MyBaseC.MyStruct.x);
While an instance of a class contains a separate copy of all instance fields of the class, there's only one copy
of each static field.
It isn't possible to use this to reference static methods or property accessors.
If the static keyword is applied to a class, all the members of the class must be static .
Classes, interfaces, and static classes may have static constructors. A static constructor is called at
some point between when the program starts and the class is instantiated.
NOTE
The static keyword has more limited uses than in C++. To compare with the C++ keyword, see Storage classes
(C++).
To demonstrate static members, consider a class that represents a company employee. Assume that the
class contains a method to count employees and a field to store the number of employees. Both the method
and the field don't belong to any one employee instance. Instead, they belong to the class of employees as a
whole. They should be declared as static members of the class.
public Employee4()
{
}
Test.x = 99;
Console.WriteLine(Test.x);
}
}
/*
Output:
0
5
99
*/
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source
for C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
Modifiers
using static directive
Static Classes and Static Class Members
unsafe (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The unsafe keyword denotes an unsafe context, which is required for any operation involving pointers. For
more information, see Unsafe Code and Pointers.
You can use the unsafe modifier in the declaration of a type or a member. The entire textual extent of the type
or member is therefore considered an unsafe context. For example, the following is a method declared with the
unsafe modifier:
The scope of the unsafe context extends from the parameter list to the end of the method, so pointers can also
be used in the parameter list:
unsafe static void FastCopy ( byte* ps, byte* pd, int count ) {...}
You can also use an unsafe block to enable the use of an unsafe code inside this block. For example:
unsafe
{
// Unsafe context: can use pointers here.
}
To compile unsafe code, you must specify the -unsafe compiler option. Unsafe code is not verifiable by the
common language runtime.
Example
// compile with: -unsafe
class UnsafeTest
{
// Unsafe method: takes pointer to int.
unsafe static void SquarePtrParam(int* p)
{
*p *= *p;
}
See also
C# Reference
C# Programming Guide
C# Keywords
fixed Statement
Unsafe Code and Pointers
Fixed Size Buffers
virtual (C# Reference)
9/3/2020 • 3 minutes to read • Edit Online
The virtual keyword is used to modify a method, property, indexer, or event declaration and allow for it to
be overridden in a derived class. For example, this method can be overridden by any class that inherits it:
The implementation of a virtual member can be changed by an overriding member in a derived class. For
more information about how to use the virtual keyword, see Versioning with the Override and New
Keywords and Knowing When to Use Override and New Keywords.
Remarks
When a virtual method is invoked, the run-time type of the object is checked for an overriding member. The
overriding member in the most derived class is called, which might be the original member, if no derived
class has overridden the member.
By default, methods are non-virtual. You cannot override a non-virtual method.
You cannot use the virtual modifier with the static , abstract , private , or override modifiers. The
following example shows a virtual property:
class MyBaseClass
{
// virtual auto-implemented property. Overrides can only
// provide specialized behavior if they implement get and set accessors.
public virtual string Name { get; set; }
Virtual properties behave like virtual methods, except for the differences in declaration and invocation syntax.
It is an error to use the virtual modifier on a static property.
A virtual inherited property can be overridden in a derived class by including a property declaration
that uses the override modifier.
Example
In this example, the Shape class contains the two coordinates x , y , and the Area() virtual method.
Different shape classes such as Circle , Cylinder , and Sphere inherit the Shape class, and the surface area
is calculated for each figure. Each derived class has its own override implementation of Area() .
Notice that the inherited classes Circle , Sphere , and Cylinder all use constructors that initialize the base
class, as shown in the following declaration.
The following program calculates and displays the appropriate area for each figure by invoking the
appropriate implementation of the Area() method, according to the object that is associated with the
method.
class TestClass
{
public class Shape
{
public const double PI = Math.PI;
protected double x, y;
public Shape()
{
}
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source
for C# syntax and usage.
See also
Polymorphism
abstract
override
new (modifier)
volatile (C# Reference)
9/3/2020 • 3 minutes to read • Edit Online
The volatile keyword indicates that a field might be modified by multiple threads that are executing at the same
time. The compiler, the runtime system, and even hardware may rearrange reads and writes to memory locations
for performance reasons. Fields that are declared volatile are not subject to these optimizations. Adding the
volatile modifier ensures that all threads will observe volatile writes performed by any other thread in the order
in which they were performed. There is no guarantee of a single total ordering of volatile writes as seen from all
threads of execution.
The volatile keyword can be applied to fields of these types:
Reference types.
Pointer types (in an unsafe context). Note that although the pointer itself can be volatile, the object that it points
to cannot. In other words, you cannot declare a "pointer to volatile."
Simple types such as sbyte , byte , short , ushort , int , uint , char , float , and bool .
An enum type with one of the following base types: byte , sbyte , short , ushort , int , or uint .
Generic type parameters known to be reference types.
IntPtr and UIntPtr.
Other types, including double and long , cannot be marked volatile because reads and writes to fields of those
types cannot be guaranteed to be atomic. To protect multi-threaded access to those types of fields, use the
Interlocked class members or protect access using the lock statement.
The volatile keyword can only be applied to fields of a class or struct . Local variables cannot be declared
volatile .
Example
The following example shows how to declare a public field variable as volatile .
class VolatileTest
{
public volatile int sharedStorage;
The following example demonstrates how an auxiliary or worker thread can be created and used to perform
processing in parallel with that of the primary thread. For more information about multithreading, see Managed
Threading.
public class Worker
{
// This method is called when the thread is started.
public void DoWork()
{
bool work = false;
while (!_shouldStop)
{
work = !work; // simulate some work
}
Console.WriteLine("Worker thread: terminating gracefully.");
}
public void RequestStop()
{
_shouldStop = true;
}
// Keyword volatile is used as a hint to the compiler that this data
// member is accessed by multiple threads.
private volatile bool _shouldStop;
}
With the volatile modifier added to the declaration of _shouldStop in place, you'll always get the same results
(similar to the excerpt shown in the preceding code). However, without that modifier on the _shouldStop member,
the behavior is unpredictable. The DoWork method may optimize the member access, resulting in reading stale
data. Because of the nature of multi-threaded programming, the number of stale reads is unpredictable. Different
runs of the program will produce somewhat different results.
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for C#
syntax and usage.
See also
C# language specification: volatile keyword
C# Reference
C# Programming Guide
C# Keywords
Modifiers
lock statement
Interlocked
Statement keywords (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
Statements are program instructions. Except as described in the topics referenced in the following table, statements
are executed in sequence. The following table lists the C# statement keywords. For more information about
statements that are not expressed with any keyword, see Statements.
C AT EGO RY C # K EY W O RDS
See also
C# Reference
Statements
C# Keywords
if-else (C# Reference)
9/3/2020 • 5 minutes to read • Edit Online
An if statement identifies which statement to run based on the value of a Boolean expression. In the following
example, the bool variable condition is set to true and then checked in the if statement. The output is
The variable is set to true. .
if (condition)
{
Console.WriteLine("The variable is set to true.");
}
else
{
Console.WriteLine("The variable is set to false.");
}
You can run the examples in this topic by placing them in the Main method of a console app.
An if statement in C# can take two forms, as the following example shows.
// if-else statement
if (condition)
{
then-statement;
}
else
{
else-statement;
}
// Next statement in the program.
In an statement, if condition evaluates to true, the then-statement runs. If condition is false, the
if-else
else-statement runs. Because condition can’t be simultaneously true and false, the then-statement and the
else-statement of an if-else statement can never both run. After the then-statement or the else-statement
runs, control is transferred to the next statement after the if statement.
In an statement that doesn’t include an else statement, if condition is true, the then-statement runs. If
if
condition is false, control is transferred to the next statement after the if statement.
Both the then-statement and the else-statement can consist of a single statement or multiple statements that
are enclosed in braces ( {} ). For a single statement, the braces are optional but recommended.
The statement or statements in the then-statement and the else-statement can be of any kind, including
another if statement nested inside the original if statement. In nested if statements, each else clause
belongs to the last if that doesn’t have a corresponding else . In the following example, Result1 appears if
both m > 10 and n > 20 evaluate to true. If m > 10 is true but n > 20 is false, Result2 appears.
// Try with m = 12 and then with m = 8.
int m = 12;
int n = 18;
if (m > 10)
if (n > 20)
{
Console.WriteLine("Result1");
}
else
{
Console.WriteLine("Result2");
}
If, instead, you want Result2 to appear when (m > 10) is false, you can specify that association by using braces
to establish the start and end of the nested if statement, as the following example shows.
Example
In the following example, you enter a character from the keyboard, and the program uses a nested if
statement to determine whether the input character is an alphabetic character. If the input character is an
alphabetic character, the program checks whether the input character is lowercase or uppercase. A message
appears for each case.
Console.Write("Enter a character: ");
char c = (char)Console.Read();
if (Char.IsLetter(c))
{
if (Char.IsLower(c))
{
Console.WriteLine("The character is lowercase.");
}
else
{
Console.WriteLine("The character is uppercase.");
}
}
else
{
Console.WriteLine("The character isn't an alphabetic character.");
}
//Sample Output:
//Enter a character: 2
//The character isn't an alphabetic character.
//Enter a character: A
//The character is uppercase.
//Enter a character: h
//The character is lowercase.
Example
You can also nest an if statement inside an else block, as the following partial code shows. The example nests
if statements inside two else blocks and one then block. The comments specify which conditions are true or
false in each block.
// Change the values of these variables to test the results.
bool Condition1 = true;
bool Condition2 = true;
bool Condition3 = true;
bool Condition4 = true;
if (Condition1)
{
// Condition1 is true.
}
else if (Condition2)
{
// Condition1 is false and Condition2 is true.
}
else if (Condition3)
{
if (Condition4)
{
// Condition1 and Condition2 are false. Condition3 and Condition4 are true.
}
else
{
// Condition1, Condition2, and Condition4 are false. Condition3 is true.
}
}
else
{
// Condition1, Condition2, and Condition3 are false.
}
Example
The following example determines whether an input character is a lowercase letter, an uppercase letter, or a
number. If all three conditions are false, the character isn’t an alphanumeric character. The example displays a
message for each case.
Console.Write("Enter a character: ");
char ch = (char)Console.Read();
if (Char.IsUpper(ch))
{
Console.WriteLine("The character is an uppercase letter.");
}
else if (Char.IsLower(ch))
{
Console.WriteLine("The character is a lowercase letter.");
}
else if (Char.IsDigit(ch))
{
Console.WriteLine("The character is a number.");
}
else
{
Console.WriteLine("The character is not alphanumeric.");
}
//Enter a character: e
//The character is a lowercase letter.
//Enter a character: 4
//The character is a number.
//Enter a character: =
//The character is not alphanumeric.
Just as a statement in the else block or the then block can be any valid statement, you can use any valid Boolean
expression for the condition. You can use logical operators such as ! , && , || , & , | , and ^ to make
compound conditions. The following code shows examples.
// NOT
bool result = true;
if (!result)
{
Console.WriteLine("The condition is true (result is false).");
}
else
{
Console.WriteLine("The condition is false (result is true).");
}
// Short-circuit AND
int m = 9;
int n = 7;
int p = 5;
if (m >= n && m >= p)
{
Console.WriteLine("Nothing is larger than m.");
}
// Short-circuit OR
if (m > n || m > p)
{
Console.WriteLine("m isn't the smallest.");
}
// NOT and OR
m = 4;
if (!(m >= n || m >= p))
{
Console.WriteLine("Now m is the smallest.");
}
// Output:
// The condition is false (result is true).
// Nothing is larger than m.
// Nothing is larger than m.
// m isn't the smallest.
// Now m is the smallest.
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
?: Operator
if-else Statement (C++)
switch
switch (C# reference)
9/3/2020 • 16 minutes to read • Edit Online
This article covers the switch statement. For information on the switch expression (introduced in C# 8.0),
see the article on switch expressions in the expressions and operators section.
switch is a selection statement that chooses a single switch section to execute from a list of candidates
based on a pattern match with the match expression.
using System;
switch (caseSwitch)
{
case 1:
Console.WriteLine("Case 1");
break;
case 2:
Console.WriteLine("Case 2");
break;
default:
Console.WriteLine("Default case");
break;
}
}
}
// The example displays the following output:
// Case 1
The switch statement is often used as an alternative to an if-else construct if a single expression is tested
against three or more conditions. For example, the following switch statement determines whether a
variable of type Color has one of three values:
using System;
using System;
switch (expr)
In C# 6 and earlier, the match expression must be an expression that returns a value of the following types:
a char.
a string.
a bool.
an integral value, such as an int or a long .
an enum value.
Starting with C# 7.0, the match expression can be any non-null expression.
using System;
switch (caseSwitch)
{
case 1:
Console.WriteLine("Case 1");
break;
case 2:
case 3:
Console.WriteLine($"Case {caseSwitch}");
break;
default:
Console.WriteLine($"An unexpected value ({caseSwitch})");
break;
}
}
}
// The example displays output like the following:
// Case 1
Only one switch section in a switch statement executes. C# doesn't allow execution to continue from one
switch section to the next. Because of this, the following code generates a compiler error, CS0163: "Control
cannot fall through from one case label (<case label>) to another."
switch (caseSwitch)
{
// The following switch section causes an error.
case 1:
Console.WriteLine("Case 1...");
// Add a break or other jump statement here.
case 2:
Console.WriteLine("... and/or Case 2");
break;
}
This requirement is usually met by explicitly exiting the switch section by using a break, goto, or return
statement. However, the following code is also valid, because it ensures that program control can't fall
through to the default switch section.
switch (caseSwitch)
{
case 1:
Console.WriteLine("Case 1...");
break;
case 2:
case 3:
Console.WriteLine("... and/or Case 2");
break;
case 4:
while (true)
Console.WriteLine("Endless looping. . . .");
default:
Console.WriteLine("Default value...");
break;
}
Execution of the statement list in the switch section with a case label that matches the match expression
begins with the first statement and proceeds through the statement list, typically until a jump statement, such
as a break , goto case , goto label , return , or throw , is reached. At that point, control is transferred
outside the switch statement or to another case label. A goto statement, if it's used, must transfer control to
a constant label. This restriction is necessary, since attempting to transfer control to a non-constant label can
have undesirable side-effects, such transferring control to an unintended location in code or creating an
endless loop.
Case labels
Each case label specifies a pattern to compare to the match expression (the caseSwitch variable in the
previous examples). If they match, control is transferred to the switch section that contains the first matching
case label. If no case label pattern matches the match expression, control is transferred to the section with the
default case label, if there's one. If there's no default case, no statements in any switch section are
executed, and control is transferred outside the switch statement.
For information on the switch statement and pattern matching, see the [Pattern matching with the switch
statement](#pattern-matching with-the-switch-statement) section.
Because C# 6 supports only the constant pattern and doesn't allow the repetition of constant values, case
labels define mutually exclusive values, and only one pattern can match the match expression. As a result, the
order in which case statements appear is unimportant.
In C# 7.0, however, because other patterns are supported, case labels need not define mutually exclusive
values, and multiple patterns can match the match expression. Because only the statements in the first switch
section that contains the matching pattern are executed, the order in which case statements appear is now
important. If C# detects a switch section whose case statement or statements are equivalent to or are subsets
of previous statements, it generates a compiler error, CS8120, "The switch case has already been handled by
a previous case."
The following example illustrates a switch statement that uses a variety of non-mutually exclusive patterns.
If you move the case 0: switch section so that it's no longer the first section in the switch statement, C#
generates a compiler error because an integer whose value is zero is a subset of all integers, which is the
pattern defined by the case int val statement.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq;
You can correct this issue and eliminate the compiler warning in one of two ways:
By changing the order of the switch sections.
By using a when clause in the case label.
case constant:
where constant is the value to test for. constant can be any of the following constant expressions:
A bool literal: either true or false .
Any integral constant, such as an int , a long , or a byte .
The name of a declared const variable.
An enumeration constant.
A char literal.
A string literal.
The constant expression is evaluated as follows:
If expr and constant are integral types, the C# equality operator determines whether the expression
returns true (that is, whether expr == constant ).
Otherwise, the value of the expression is determined by a call to the static Object.Equals(expr, constant)
method.
The following example uses the constant pattern to determine whether a particular date is a weekend, the
first day of the work week, the last day of the work week, or the middle of the work week. It evaluates the
DateTime.DayOfWeek property of the current day against the members of the DayOfWeek enumeration.
using System;
class Program
{
static void Main()
{
switch (DateTime.Now.DayOfWeek)
{
case DayOfWeek.Sunday:
case DayOfWeek.Saturday:
Console.WriteLine("The weekend");
break;
case DayOfWeek.Monday:
Console.WriteLine("The first day of the work week.");
break;
case DayOfWeek.Friday:
Console.WriteLine("The last day of the work week.");
break;
default:
Console.WriteLine("The middle of the work week.");
break;
}
}
}
// The example displays output like the following:
// The middle of the work week.
The following example uses the constant pattern to handle user input in a console application that simulates
an automatic coffee machine.
using System;
class Example
{
static void Main()
{
Console.WriteLine("Coffee sizes: 1=small 2=medium 3=large");
Console.Write("Please enter your selection: ");
string str = Console.ReadLine();
int cost = 0;
Type pattern
The type pattern enables concise type evaluation and conversion. When used with the switch statement to
perform pattern matching, it tests whether an expression can be converted to a specified type and, if it can be,
casts it to a variable of that type. Its syntax is:
where type is the name of the type to which the result of expr is to be converted, and varname is the object to
which the result of expr is converted if the match succeeds. The compile-time type of expr may be a generic
type parameter, starting with C# 7.1.
The case expression is true if any of the following is true:
expr is an instance of the same type as type.
expr is an instance of a type that derives from type. In other words, the result of expr can be upcast to
an instance of type.
expr has a compile-time type that is a base class of type, and expr has a runtime type that is type or is
derived from type. The compile-time type of a variable is the variable's type as defined in its type
declaration. The runtime type of a variable is the type of the instance that is assigned to that variable.
expr is an instance of a type that implements the type interface.
If the case expression is true, varname is definitely assigned and has local scope within the switch section
only.
Note that null doesn't match a type. To match a null , you use the following case label:
case null:
The following example uses the type pattern to provide information about various kinds of collection types.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
class Example
{
static void Main(string[] args)
{
int[] values = { 2, 4, 6, 8, 10 };
ShowCollectionInformation(values);
Instead of object , you could make a generic method, using the type of the collection as the type parameter,
as shown in the following code:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
class Example
{
static void Main(string[] args)
{
int[] values = { 2, 4, 6, 8, 10 };
ShowCollectionInformation(values);
The generic version is different than the first sample in two ways. First, you can't use the null case. You can't
use any constant case because the compiler can't convert any arbitrary type T to any type other than
object . What had been the default case now tests for a non-null object . That means the default case
tests only for null .
Without pattern matching, this code might be written as follows. The use of type pattern matching produces
more compact, readable code by eliminating the need to test whether the result of a conversion is a null or
to perform repeated casts.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
class Example
{
static void Main(string[] args)
{
int[] values = { 2, 4, 6, 8, 10 };
ShowCollectionInformation(values);
using System;
Note that the when clause in the example that attempts to test whether a Shape object is null doesn't
execute. The correct type pattern to test for a null is case null: .
C# language specification
For more information, see The switch statement in the C# Language Specification. The language specification
is the definitive source for C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
if-else
Pattern Matching
do (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The do statement executes a statement or a block of statements while a specified Boolean expression evaluates
to true . Because that expression is evaluated after each execution of the loop, a do-while loop executes one or
more times. This differs from the while loop, which executes zero or more times.
At any point within the do statement block, you can break out of the loop by using the break statement.
You can step directly to the evaluation of the while expression by using the continue statement. If the expression
evaluates to true , execution continues at the first statement in the loop. Otherwise, execution continues at the
first statement after the loop.
You can also exit a do-while loop by the goto, return, or throw statements.
Example
The following example shows the usage of the do statement. Select Run to run the example code. After that you
can modify the code and run it again.
int n = 0;
do
{
Console.WriteLine(n);
n++;
} while (n < 5);
C# language specification
For more information, see The do statement section of the C# language specification.
See also
C# Reference
C# Programming Guide
C# Keywords
while statement
for (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
The for statement executes a statement or a block of statements while a specified Boolean expression
evaluates to true .
At any point within the for statement block, you can break out of the loop by using the break statement, or
step to the next iteration in the loop by using the continue statement. You can also exit a for loop by the goto,
return, or throw statements.
All three sections are optional. The body of the loop is either a statement or a block of statements.
The following example shows the for statement with all of the sections defined:
int i = 0
i < 5
i++
Examples
The following example illustrates several less common usages of the for statement sections: assigning a value
to an external loop variable in the initializer section, invoking a method in both the initializer and the iterator
sections, and changing the values of two variables in the iterator section. Select Run to run the example code.
After that you can modify the code and run it again.
int i;
int j = 10;
for (i = 0, Console.WriteLine($"Start: i={i}, j={j}"); i < j; i++, j--, Console.WriteLine($"Step: i={i}, j=
{j}"))
{
// Body of the loop.
}
for ( ; ; )
{
// Body of the loop.
}
C# language specification
For more information, see The for statement section of the C# language specification.
See also
C# Reference
C# Programming Guide
C# Keywords
foreach, in
foreach, in (C# reference)
9/3/2020 • 3 minutes to read • Edit Online
The foreach statement executes a statement or a block of statements for each element in an instance of the
type that implements the System.Collections.IEnumerable or System.Collections.Generic.IEnumerable<T>
interface, as the following example shows:
The foreach statement isn't limited to those types. You can use it with an instance of any type that satisfies
the following conditions:
a type has the public parameterless GetEnumerator method whose return type is either class, struct, or
interface type,
the return type of the GetEnumerator method has the public Current property and the public
parameterless MoveNext method whose return type is Boolean.
The following example uses the foreach statement with an instance of the System.Span<T> type, which
doesn't implement any interfaces:
Beginning with C# 7.3, if the enumerator's Current property returns a reference return value ( ref T where
T is the type of a collection element), you can declare an iteration variable with the ref or ref readonly
modifier, as the following example shows:
public class ForeachRefExample
{
public static void Main()
{
Span<int> storage = stackalloc int[10];
int num = 0;
foreach (ref int item in storage)
{
item = num++;
}
Beginning with C# 8.0, you can use the await foreach statement to consume an asynchronous stream of
data, that is, the collection type that implements the IAsyncEnumerable<T> interface. Each iteration of the
loop may be suspended while the next element is retrieved asynchronously. The following example shows
how to use the await foreach statement:
By default, stream elements are processed in the captured context. If you want to disable capturing of the
context, use the TaskAsyncEnumerableExtensions.ConfigureAwait extension method. For more information
about synchronization contexts and capturing the current context, see Consuming the Task-based
asynchronous pattern. For more information about asynchronous streams, see the Asynchronous streams
section of the What's new in C# 8.0 article.
At any point within the foreach statement block, you can break out of the loop by using the break
statement, or step to the next iteration in the loop by using the continue statement. You can also exit a
foreach loop by the goto, return, or throw statements.
If the foreach statement is applied to null , a NullReferenceException is thrown. If the source collection of
the foreach statement is empty, the body of the foreach loop isn't executed and skipped.
You can also explicitly specify the type of an iteration variable, as the following code shows:
In the preceding form, type T of a collection element must be implicitly or explicitly convertible to type V
of an iteration variable. If an explicit conversion from T to V fails at run time, the foreach statement
throws an InvalidCastException. For example, if T is a non-sealed class type, V can be any interface type,
even the one that T doesn't implement. At run time, the type of a collection element may be the one that
derives from T and actually implements V . If that's not the case, an InvalidCastException is thrown.
C# language specification
For more information, see The foreach statement section of the C# language specification.
See also
C# reference
C# keywords
Using foreach with arrays
for statement
while (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The while statement executes a statement or a block of statements while a specified Boolean expression
evaluates to true . Because that expression is evaluated before each execution of the loop, a while loop
executes zero or more times. This differs from the do loop, which executes one or more times.
At any point within the while statement block, you can break out of the loop by using the break statement.
You can step directly to the evaluation of the while expression by using the continue statement. If the expression
evaluates to true , execution continues at the first statement in the loop. Otherwise, execution continues at the
first statement after the loop.
You can also exit a while loop by the goto, return, or throw statements.
Example
The following example shows the usage of the while statement. Select Run to run the example code. After that
you can modify the code and run it again.
int n = 0;
while (n < 5)
{
Console.WriteLine(n);
n++;
}
C# language specification
For more information, see The while statement section of the C# language specification.
See also
C# Reference
C# Programming Guide
C# Keywords
do statement
break (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The break statement terminates the closest enclosing loop or switch statement in which it appears. Control is
passed to the statement that follows the terminated statement, if any.
Example
In this example, the conditional statement contains a counter that is supposed to count from 1 to 100; however,
the break statement terminates the loop after 4 counts.
class BreakTest
{
static void Main()
{
for (int i = 1; i <= 100; i++)
{
if (i == 5)
{
break;
}
Console.WriteLine(i);
}
Example
This example demonstrates the use of break in a switch statement.
class Switch
{
static void Main()
{
Console.Write("Enter your selection (1, 2, or 3): ");
string s = Console.ReadLine();
int n = Int32.Parse(s);
switch (n)
{
case 1:
Console.WriteLine("Current value is 1");
break;
case 2:
Console.WriteLine("Current value is 2");
break;
case 3:
Console.WriteLine("Current value is 3");
break;
default:
Console.WriteLine("Sorry, invalid selection.");
break;
}
Sample Output:
Enter your selection (1, 2, or 3): 1
Current value is 1
*/
Example
In this example, the break statement is used to break out of an inner nested loop, and return control to the outer
loop. Control is only returned one level up in the nested loops.
class BreakInNestedLoops
{
static void Main(string[] args)
{
int[] numbers = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
char[] letters = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' };
// Outer loop.
for (int i = 0; i < numbers.Length; i++)
{
Console.WriteLine($"num = {numbers[i]}");
// Inner loop.
for (int j = 0; j < letters.Length; j++)
{
if (j == i)
{
// Return control to outer loop.
break;
}
Console.Write($" {letters[j]} ");
}
Console.WriteLine();
}
/*
* Output:
num = 0
num = 1
a
num = 2
a b
num = 3
a b c
num = 4
a b c d
num = 5
a b c d e
num = 6
a b c d e f
num = 7
a b c d e f g
num = 8
a b c d e f g h
num = 9
a b c d e f g h i
*/
Example
In this example, the break statement is only used to break out of the current branch during each iteration of the
loop. The loop itself is unaffected by the instances of break that belong to the nested switch statement.
class BreakFromSwitchInsideLoop
{
static void Main(string[] args)
{
// loop 1 to 3
for (int i = 1; i <= 3; i++)
{
switch(i)
{
case 1:
Console.WriteLine("Current value is 1");
break;
case 2:
Console.WriteLine("Current value is 2");
break;
case 3:
Console.WriteLine("Current value is 3");
break;
default:
Console.WriteLine("This shouldn't happen.");
break;
}
}
/*
* Output:
Current value is 1
Current value is 2
Current value is 3
*/
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
switch
continue (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The continue statement passes control to the next iteration of the enclosing while, do, for, or foreach statement
in which it appears.
Example
In this example, a counter is initialized to count from 1 to 10. By using the continue statement in conjunction
with the expression (i < 9) , the statements between continue and the end of the for body are skipped.
class ContinueTest
{
static void Main()
{
for (int i = 1; i <= 10; i++)
{
if (i < 9)
{
continue;
}
Console.WriteLine(i);
}
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
break Statement
goto (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The goto statement transfers the program control directly to a labeled statement.
A common use of goto is to transfer control to a specific switch-case label or the default label in a switch
statement.
The goto statement is also useful to get out of deeply nested loops.
Example
The following example demonstrates using goto in a switch statement.
class SwitchTest
{
static void Main()
{
Console.WriteLine("Coffee sizes: 1=Small 2=Medium 3=Large");
Console.Write("Please enter your selection: ");
string s = Console.ReadLine();
int n = int.Parse(s);
int cost = 0;
switch (n)
{
case 1:
cost += 25;
break;
case 2:
cost += 25;
goto case 1;
case 3:
cost += 50;
goto case 1;
default:
Console.WriteLine("Invalid selection.");
break;
}
if (cost != 0)
{
Console.WriteLine($"Please insert {cost} cents.");
}
Console.WriteLine("Thank you for your business.");
Sample Output:
Coffee sizes: 1=Small 2=Medium 3=Large
Please enter your selection: 2
Please insert 50 cents.
Thank you for your business.
*/
Example
The following example demonstrates using goto to break out from nested loops.
// Read input.
Console.Write("Enter the number to search for: ");
// Input a string.
string myNumber = Console.ReadLine();
// Search.
for (int i = 0; i < x; i++)
{
for (int j = 0; j < y; j++)
{
if (array[i, j].Equals(myNumber))
{
goto Found;
}
}
}
Found:
Console.WriteLine($"The number {myNumber} is found.");
Finish:
Console.WriteLine("End of search.");
Sample Output
Enter the number to search for: 44
The number 44 is found.
End of search.
*/
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
goto Statement (C++)
return (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The return statement terminates execution of the method in which it appears and returns control to the
calling method. It can also return an optional value. If the method is a void type, the return statement can be
omitted.
If the return statement is inside a try block, the finally block, if one exists, will be executed before control
returns to the calling method.
Example
In the following example, the method CalculateArea() returns the local variable area as a double value.
class ReturnTest
{
static double CalculateArea(int r)
{
double area = r * r * Math.PI;
return area;
}
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
return Statement
throw (C# Reference)
9/3/2020 • 3 minutes to read • Edit Online
Remarks
The syntax of throw is:
throw [e];
where e is an instance of a class derived from System.Exception. The following example uses the throw
statement to throw an IndexOutOfRangeException if the argument passed to a method named GetNumber does
not correspond to a valid index of an internal array.
using System;
Method callers then use a try-catch or try-catch-finally block to handle the thrown exception. The following
example handles the exception thrown by the GetNumber method.
using System;
using System;
IMPORTANT
You can also use the throw e syntax in a catch block to instantiate a new exception that you pass on to the caller. In
this case, the stack trace of the original exception, which is available from the StackTrace property, is not preserved.
the null-coalescing operator. In the following example, a throw expression is used with a null-coalescing
operator to throw an exception if the string assigned to a Name property is null .
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Reference
C# Programming Guide
try-catch
C# Keywords
How to: Explicitly Throw Exceptions
try-catch (C# Reference)
9/3/2020 • 8 minutes to read • Edit Online
The try-catch statement consists of a try block followed by one or more catch clauses, which specify
handlers for different exceptions.
When an exception is thrown, the common language runtime (CLR) looks for the catch statement that
handles this exception. If the currently executing method does not contain such a catch block, the CLR looks
at the method that called the current method, and so on up the call stack. If no catch block is found, then the
CLR displays an unhandled exception message to the user and stops execution of the program.
The try block contains the guarded code that may cause the exception. The block is executed until an
exception is thrown or it is completed successfully. For example, the following attempt to cast a null object
raises the NullReferenceException exception:
object o2 = null;
try
{
int i2 = (int)o2; // Error
}
Although the catch clause can be used without arguments to catch any type of exception, this usage is not
recommended. In general, you should only catch those exceptions that you know how to recover from.
Therefore, you should always specify an object argument derived from System.Exception For example:
catch (InvalidCastException e)
{
}
It is possible to use more than one specific catch clause in the same try-catch statement. In this case, the
order of the catch clauses is important because the catch clauses are examined in order. Catch the more
specific exceptions before the less specific ones. The compiler produces an error if you order your catch blocks
so that a later block can never be reached.
Using catch arguments is one way to filter for the exceptions you want to handle. You can also use an
exception filter that further examines the exception to decide whether to handle it. If the exception filter
returns false, then the search for a handler continues.
Exception filters are preferable to catching and rethrowing (explained below) because filters leave the stack
unharmed. If a later handler dumps the stack, you can see where the exception originally came from, rather
than just the last place it was rethrown. A common use of exception filter expressions is logging. You can
create a filter that always returns false that also outputs to a log, you can log exceptions as they go by without
having to handle them and rethrow.
A throw statement can be used in a catch block to re-throw the exception that is caught by the catch
statement. The following example extracts source information from an IOException exception, and then throws
the exception to the parent method.
catch (FileNotFoundException e)
{
// FileNotFoundExceptions are handled here.
}
catch (IOException e)
{
// Extract some information from this exception, and then
// throw it to the parent method.
if (e.Source != null)
Console.WriteLine("IOException source: {0}", e.Source);
throw;
}
You can catch one exception and throw a different exception. When you do this, specify the exception that you
caught as the inner exception, as shown in the following example.
catch (InvalidCastException e)
{
// Perform some action here, and then throw a new exception.
throw new YourCustomException("Put your error message here.", e);
}
You can also re-throw an exception when a specified condition is true, as shown in the following example.
catch (InvalidCastException e)
{
if (e.Data == null)
{
throw;
}
else
{
// Take some action.
}
}
NOTE
It is also possible to use an exception filter to get a similar result in an often cleaner fashion (as well as not modifying
the stack, as explained earlier in this document). The following example has a similar behavior for callers as the previous
example. The function throws the InvalidCastException back to the caller when e.Data is null .
From inside a try block, initialize only variables that are declared therein. Otherwise, an exception can occur
before the execution of the block is completed. For example, in the following code example, the variable n is
initialized inside the try block. An attempt to use this variable outside the try block in the Write(n)
statement will generate a compiler error.
static void Main()
{
int n;
try
{
// Do not initialize this variable here.
n = 123;
}
catch
{
}
// Error: Use of unassigned local variable 'n'.
Console.Write(n);
}
To catch the exception, await the task in a try block, and catch the exception in the associated catch block.
For an example, see the Async method example section.
A task can be in a faulted state because multiple exceptions occurred in the awaited async method. For
example, the task might be the result of a call to Task.WhenAll. When you await such a task, only one of the
exceptions is caught, and you can't predict which exception will be caught. For an example, see the
Task.WhenAll example section.
Example
In the following example, the try block contains a call to the ProcessString method that may cause an
exception. The catch clause contains the exception handler that just displays a message on the screen. When
the throw statement is called from inside ProcessString , the system looks for the catch statement and
displays the message Exception caught .
class TryFinallyTest
{
static void ProcessString(string s)
{
if (s == null)
{
throw new ArgumentNullException();
}
}
try
{
ProcessString(s);
}
catch (Exception e)
{
Console.WriteLine("{0} Exception caught.", e);
}
}
}
/*
Output:
System.ArgumentNullException: Value cannot be null.
at TryFinallyTest.Main() Exception caught.
* */
try
{
string result = await theTask;
Debug.WriteLine("Result: " + result);
}
catch (Exception ex)
{
Debug.WriteLine("Exception Message: " + ex.Message);
}
Debug.WriteLine("Task IsCanceled: " + theTask.IsCanceled);
Debug.WriteLine("Task IsFaulted: " + theTask.IsFaulted);
if (theTask.Exception != null)
{
Debug.WriteLine("Task Exception Message: "
+ theTask.Exception.Message);
Debug.WriteLine("Task Inner Exception Message: "
+ theTask.Exception.InnerException.Message);
}
}
Task.WhenAll example
The following example illustrates exception handling where multiple tasks can result in multiple exceptions.
The try block awaits the task that's returned by a call to Task.WhenAll. The task is complete when the three
tasks to which WhenAll is applied are complete.
Each of the three tasks causes an exception. The catch block iterates through the exceptions, which are found
in the Exception.InnerExceptions property of the task that was returned by Task.WhenAll.
public async Task DoMultipleAsync()
{
Task theTask1 = ExcAsync(info: "First Task");
Task theTask2 = ExcAsync(info: "Second Task");
Task theTask3 = ExcAsync(info: "Third Task");
try
{
await allTasks;
}
catch (Exception ex)
{
Debug.WriteLine("Exception: " + ex.Message);
Debug.WriteLine("Task IsFaulted: " + allTasks.IsFaulted);
foreach (var inEx in allTasks.Exception.InnerExceptions)
{
Debug.WriteLine("Task Inner Exception: " + inEx.Message);
}
}
}
// Output:
// Exception: Error-First Task
// Task IsFaulted: True
// Task Inner Exception: Error-First Task
// Task Inner Exception: Error-Second Task
// Task Inner Exception: Error-Third Task
C# language specification
For more information, see The try statement section of the C# language specification.
See also
C# Reference
C# Programming Guide
C# Keywords
try, throw, and catch Statements (C++)
throw
try-finally
How to: Explicitly Throw Exceptions
try-finally (C# Reference)
9/3/2020 • 3 minutes to read • Edit Online
By using a finally block, you can clean up any resources that are allocated in a try block, and you can run code
even if an exception occurs in the try block. Typically, the statements of a finally block run when control
leaves a try statement. The transfer of control can occur as a result of normal execution, of execution of a
break , continue , goto , or return statement, or of propagation of an exception out of the try statement.
Within a handled exception, the associated finally block is guaranteed to be run. However, if the exception is
unhandled, execution of the finally block is dependent on how the exception unwind operation is triggered.
That, in turn, is dependent on how your computer is set up.
Usually, when an unhandled exception ends an application, whether or not the finally block is run is not
important. However, if you have statements in a finally block that must be run even in that situation, one
solution is to add a catch block to the try - finally statement. Alternatively, you can catch the exception that
might be thrown in the try block of a try - finally statement higher up the call stack. That is, you can catch
the exception in the method that calls the method that contains the try - finally statement, or in the method
that calls that method, or in any method in the call stack. If the exception is not caught, execution of the finally
block depends on whether the operating system chooses to trigger an exception unwind operation.
Example
In the following example, an invalid conversion statement causes a System.InvalidCastException exception. The
exception is unhandled.
public class ThrowTestA
{
static void Main()
{
int i = 123;
string s = "Some string";
object obj = s;
try
{
// Invalid conversion; obj contains a string, not a numeric type.
i = (int)obj;
In the following example, an exception from the TryCast method is caught in a method farther up the call stack.
public class ThrowTestB
{
static void Main()
{
try
{
// TryCast produces an unhandled exception.
TryCast();
}
catch (Exception ex)
{
// Catch the exception that is unhandled in TryCast.
Console.WriteLine
("Catching the {0} exception triggers the finally block.",
ex.GetType());
try
{
// Invalid conversion; obj contains a string, not a numeric type.
i = (int)obj;
C# language specification
For more information, see The try statement section of the C# language specification.
See also
C# Reference
C# Programming Guide
C# Keywords
try, throw, and catch Statements (C++)
throw
try-catch
How to: Explicitly Throw Exceptions
try-catch-finally (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
A common usage of catch and finally together is to obtain and use resources in a try block, deal with
exceptional circumstances in a catch block, and release the resources in the finally block.
For more information and examples on re-throwing exceptions, see try-catch and Throwing Exceptions. For more
information about the finally block, see try-finally.
Example
public class EHClass
{
void ReadFile(int index)
{
// To run this code, substitute a valid path from your local machine
string path = @"c:\users\public\test.txt";
System.IO.StreamReader file = new System.IO.StreamReader(path);
char[] buffer = new char[10];
try
{
file.ReadBlock(buffer, index, buffer.Length);
}
catch (System.IO.IOException e)
{
Console.WriteLine("Error reading from {0}. Message = {1}", path, e.Message);
}
finally
{
if (file != null)
{
file.Close();
}
}
// Do something with buffer...
}
}
C# language specification
For more information, see The try statement section of the C# language specification.
See also
C# Reference
C# Programming Guide
C# Keywords
try, throw, and catch Statements (C++)
throw
How to: Explicitly Throw Exceptions
using Statement
Checked and Unchecked (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
C# statements can execute in either checked or unchecked context. In a checked context, arithmetic overflow
raises an exception. In an unchecked context, arithmetic overflow is ignored and the result is truncated by
discarding any high-order bits that don't fit in the destination type.
checked Specify checked context.
unchecked Specify unchecked context.
The following operations are affected by the overflow checking:
Expressions using the following predefined operators on integral types:
++ , -- , unary - , + , - , * , /
Explicit numeric conversions between integral types, or from float or double to an integral type.
If neither checked nor unchecked is specified, the default context for non-constant expressions (expressions that
are evaluated at run time) is defined by the value of the -checked compiler option. By default the value of that
option is unset and arithmetic operations are executed in an unchecked context.
For constant expressions (expressions that can be fully evaluated at compile time), the default context is always
checked. Unless a constant expression is explicitly placed in an unchecked context, overflows that occur during the
compile-time evaluation of the expression cause compile-time errors.
See also
C# Reference
C# Programming Guide
C# Keywords
Statement Keywords
checked (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The checked keyword is used to explicitly enable overflow checking for integral-type arithmetic operations and
conversions.
By default, an expression that contains only constant values causes a compiler error if the expression produces a
value that is outside the range of the destination type. If the expression contains one or more non-constant
values, the compiler does not detect the overflow. Evaluating the expression assigned to i2 in the following
example does not cause a compiler error.
// The following example, which includes variable ten, does not cause
// a compiler error.
int ten = 10;
int i2 = 2147483647 + ten;
By default, these non-constant expressions are not checked for overflow at run time either, and they do not raise
overflow exceptions. The previous example displays -2,147,483,639 as the sum of two positive integers.
Overflow checking can be enabled by compiler options, environment configuration, or use of the checked
keyword. The following examples demonstrate how to use a checked expression or a checked block to detect the
overflow that is produced by the previous sum at run time. Both examples raise an overflow exception.
// Checked expression.
Console.WriteLine(checked(2147483647 + ten));
// Checked block.
checked
{
int i3 = 2147483647 + ten;
Console.WriteLine(i3);
}
Example
This sample shows how to use checked to enable overflow checking at run time.
class OverFlowTest
{
// Set maxIntValue to the maximum value for integers.
static int maxIntValue = 2147483647;
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
Checked and Unchecked
unchecked
unchecked (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The unchecked keyword is used to suppress overflow-checking for integral-type arithmetic operations and
conversions.
In an unchecked context, if an expression produces a value that is outside the range of the destination type, the
overflow is not flagged. For example, because the calculation in the following example is performed in an
unchecked block or expression, the fact that the result is too large for an integer is ignored, and int1 is assigned
the value -2,147,483,639.
unchecked
{
int1 = 2147483647 + 10;
}
int1 = unchecked(ConstantMax + 10);
If the unchecked environment is removed, a compilation error occurs. The overflow can be detected at compile
time because all the terms of the expression are constants.
Expressions that contain non-constant terms are unchecked by default at compile time and run time. See checked
for information about enabling a checked environment.
Because checking for overflow takes time, the use of unchecked code in situations where there is no danger of
overflow might improve performance. However, if overflow is a possibility, a checked environment should be
used.
Example
This sample shows how to use the unchecked keyword.
class UncheckedDemo
{
static void Main(string[] args)
{
// int.MaxValue is 2,147,483,647.
const int ConstantMax = int.MaxValue;
int int1;
int int2;
int variableMax = 2147483647;
// The following statements are checked by default at compile time. They do not
// compile.
//int1 = 2147483647 + 10;
//int1 = ConstantMax + 10;
// To enable the assignments to int1 to compile and run, place them inside
// an unchecked block or expression. The following statements compile and
// run.
unchecked
{
int1 = 2147483647 + 10;
}
int1 = unchecked(ConstantMax + 10);
// To catch the overflow in the assignment to int2 at run time, put the
// declaration in a checked block or expression. The following
// statements compile but raise an overflow exception at run time.
checked
{
//int2 = variableMax + 10;
}
//int2 = checked(variableMax + 10);
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
Checked and Unchecked
checked
fixed Statement (C# Reference)
9/3/2020 • 3 minutes to read • Edit Online
The fixed statement prevents the garbage collector from relocating a movable variable. The fixed statement
is only permitted in an unsafe context. You can also use the fixed keyword to create fixed size buffers.
The fixed statement sets a pointer to a managed variable and "pins" that variable during the execution of the
statement. Pointers to movable managed variables are useful only in a fixed context. Without a fixed
context, garbage collection could relocate the variables unpredictably. The C# compiler only lets you assign a
pointer to a managed variable in a fixed statement.
class Point
{
public int x;
public int y;
}
You can initialize a pointer by using an array, a string, a fixed-size buffer, or the address of a variable. The
following example illustrates the use of variable addresses, arrays, and strings:
// The following two assignments are equivalent. Each assigns the address
// of the first element in array arr to pointer p.
Starting with C# 7.3, the fixed statement operates on additional types beyond arrays, strings, fixed size
buffers, or unmanaged variables. Any type that implements a method named GetPinnableReference can be
pinned. The GetPinnableReference must return a ref variable of an unmanaged type. The .NET types
System.Span<T> and System.ReadOnlySpan<T> introduced in .NET Core 2.0 make use of this pattern and can
be pinned. This is shown in the following example:
If you are creating types that should participate in this pattern, see Span<T>.GetPinnableReference() for an
example of implementing the pattern.
Multiple pointers can be initialized in one statement if they are all the same type:
To initialize pointers of different types, simply nest fixed statements, as shown in the following example.
After the code in the statement is executed, any pinned variables are unpinned and subject to garbage
collection. Therefore, do not point to those variables outside the fixed statement. The variables declared in the
fixed statement are scoped to that statement, making this easier:
Pointers initialized in fixed statements are readonly variables. If you want to modify the pointer value, you
must declare a second pointer variable, and modify that. The variable declared in the fixed statement cannot
be modified:
You can allocate memory on the stack, where it is not subject to garbage collection and therefore does not need
to be pinned. To do that, use a stackalloc expression.
C# language specification
For more information, see The fixed statement section of the C# language specification.
See also
C# Reference
C# Programming Guide
C# Keywords
unsafe
Pointer types
Fixed Size Buffers
lock statement (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
The lock statement acquires the mutual-exclusion lock for a given object, executes a statement block, and then
releases the lock. While a lock is held, the thread that holds the lock can again acquire and release the lock. Any
other thread is blocked from acquiring the lock and waits until the lock is released.
The lock statement is of the form
lock (x)
{
// Your code...
}
object __lockObj = x;
bool __lockWasTaken = false;
try
{
System.Threading.Monitor.Enter(__lockObj, ref __lockWasTaken);
// Your code...
}
finally
{
if (__lockWasTaken) System.Threading.Monitor.Exit(__lockObj);
}
Since the code uses a try...finally block, the lock is released even if an exception is thrown within the body of a
lock statement.
You can't use the await operator in the body of a lock statement.
Guidelines
When you synchronize thread access to a shared resource, lock on a dedicated object instance (for example,
private readonly object balanceLock = new object(); ) or another instance that is unlikely to be used as a lock
object by unrelated parts of the code. Avoid using the same lock object instance for different shared resources, as
it might result in deadlock or lock contention. In particular, avoid using the following as lock objects:
, as it might be used by the callers as a lock.
this
Type instances, as those might be obtained by the typeof operator or reflection.
string instances, including string literals, as those might be interned.
Hold a lock for as short time as possible to reduce lock contention.
Example
The following example defines an Account class that synchronizes access to its private balance field by locking
on a dedicated balanceLock instance. Using the same instance for locking ensures that the balance field cannot
be updated simultaneously by two threads attempting to call the Debit or Credit methods simultaneously.
using System;
using System;
using System.Threading.Tasks;
decimal appliedAmount = 0;
lock (balanceLock)
{
if (balance >= amount)
{
balance -= amount;
appliedAmount = amount;
}
}
return appliedAmount;
}
lock (balanceLock)
{
balance += amount;
}
}
class AccountTest
{
static async Task Main()
{
var account = new Account(1000);
var tasks = new Task[100];
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = Task.Run(() => Update(account));
}
await Task.WhenAll(tasks);
Console.WriteLine($"Account's balance is {account.GetBalance()}");
// Output:
// Account's balance is 2000
}
C# language specification
For more information, see The lock statement section of the C# language specification.
See also
C# reference
C# keywords
System.Threading.Monitor
System.Threading.SpinLock
System.Threading.Interlocked
Overview of synchronization primitives
Method Parameters (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
Parameters declared for a method without in, ref or out, are passed to the called method by value. That value can
be changed in the method, but the changed value will not be retained when control passes back to the calling
procedure. By using a method parameter keyword, you can change this behavior.
This section describes the keywords you can use when declaring method parameters:
params specifies that this parameter may take a variable number of arguments.
in specifies that this parameter is passed by reference but is only read by the called method.
ref specifies that this parameter is passed by reference and may be read or written by the called method.
out specifies that this parameter is passed by reference and is written by the called method.
See also
C# Reference
C# Programming Guide
C# Keywords
params (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
By using the params keyword, you can specify a method parameter that takes a variable number of arguments.
The parameter type must be a single-dimensional array.
No additional parameters are permitted after the params keyword in a method declaration, and only one params
keyword is permitted in a method declaration.
If the declared type of the params parameter is not a single-dimensional array, compiler error CS0225 occurs.
When you call a method with a params parameter, you can pass in:
A comma-separated list of arguments of the type of the array elements.
An array of arguments of the specified type.
No arguments. If you send no arguments, the length of the params list is zero.
Example
The following example demonstrates various ways in which arguments can be sent to a params parameter.
public class MyClass
{
public static void UseParams(params int[] list)
{
for (int i = 0; i < list.Length; i++)
{
Console.Write(list[i] + " ");
}
Console.WriteLine();
}
// The following call does not cause an error, but the entire
// integer array becomes the first element of the params array.
UseParams2(myIntArray);
}
}
/*
Output:
1 2 3 4
1 a test
5 6 7 8 9
2 b test again
System.Int32[]
*/
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for C#
syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
Method Parameters
in parameter modifier (C# Reference)
9/3/2020 • 5 minutes to read • Edit Online
The in keyword causes arguments to be passed by reference. It makes the formal parameter an alias for the
argument, which must be a variable. In other words, any operation on the parameter is made on the argument.
It is like the ref or out keywords, except that in arguments cannot be modified by the called method. Whereas
ref arguments may be modified, out arguments must be modified by the called method, and those
modifications are observable in the calling context.
The preceding example demonstrates that the in modifier is usually unnecessary at the call site. It is only
required in the method declaration.
NOTE
The in keyword can also be used with a generic type parameter to specify that the type parameter is contravariant, as
part of a foreach statement, or as part of a join clause in a LINQ query. For more information on the use of the
in keyword in these contexts, see in, which provides links to all those uses.
Variables passed as in arguments must be initialized before being passed in a method call. However, the
called method may not assign a value or modify the argument.
The in parameter modifier is available in C# 7.2 and later. Previous versions generate compiler error CS8107
("Feature 'readonly references' is not available in C# 7.0. Please use language version 7.2 or greater.") To
configure the compiler language version, see Select the C# language version.
The in , ref , and out keywords are not considered part of the method signature for the purpose of
overload resolution. Therefore, methods cannot be overloaded if the only difference is that one method takes a
ref or in argument and the other takes an out argument. The following code, for example, will not
compile:
class CS0663_Example
{
// Compiler error CS0663: "Cannot define overloaded
// methods that differ only on in, ref and out".
public void SampleMethod(in int i) { }
public void SampleMethod(ref int i) { }
}
Now, suppose another method using by value arguments was available. The results change as shown in the
following code:
The only method call where the argument is passed by reference is the final one.
NOTE
The preceding code uses int as the argument type for simplicity. Because int is no larger than a reference in most
modern machines, there is no benefit to passing a single int as a readonly reference.
Limitations on in parameters
You can't use the in , ref , and out keywords for the following kinds of methods:
Async methods, which you define by using the async modifier.
Iterator methods, which include a yield return or yield break statement.
The first argument of an extension method cannot have the in modifier unless that argument is a struct.
The first argument of an extension method where that argument is a generic type (even when that type is
constrained to be a struct.)
C# Language Specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
Method Parameters
Write safe efficient code
ref (C# Reference)
9/3/2020 • 9 minutes to read • Edit Online
The ref keyword indicates a value that is passed by reference. It is used in four different contexts:
In a method signature and in a method call, to pass an argument to a method by reference. For more
information, see Passing an argument by reference.
In a method signature, to return a value to the caller by reference. For more information, see Reference
return values.
In a member body, to indicate that a reference return value is stored locally as a reference that the caller
intends to modify or, in general, a local variable accesses another value by reference. For more
information, see Ref locals.
In a struct declaration to declare a ref struct or a readonly ref struct . For more information, see
the ref struct section of the Structure types article.
NOTE
Do not confuse the concept of passing by reference with the concept of reference types. The two concepts are not
the same. A method parameter can be modified by ref regardless of whether it is a value type or a reference type.
There is no boxing of a value type when it is passed by reference.
To use a ref parameter, both the method definition and the calling method must explicitly use the ref
keyword, as shown in the following example.
int number = 1;
Method(ref number);
Console.WriteLine(number);
// Output: 45
An argument that is passed to a ref or in parameter must be initialized before it is passed. This differs
from out parameters, whose arguments do not have to be explicitly initialized before they are passed.
Members of a class can't have signatures that differ only by ref , in , or out . A compiler error occurs if
the only difference between two members of a type is that one of them has a ref parameter and the other
has an out , or in parameter. The following code, for example, doesn't compile.
class CS0663_Example
{
// Compiler error CS0663: "Cannot define overloaded
// methods that differ only on ref and out".
public void SampleMethod(out int i) { }
public void SampleMethod(ref int i) { }
}
However, methods can be overloaded when one method has a ref , in , or out parameter and the other
has a value parameter, as shown in the following example.
class RefOverloadExample
{
public void SampleMethod(int i) { }
public void SampleMethod(ref int i) { }
}
In other situations that require signature matching, such as hiding or overriding, in , ref , and out are
part of the signature and don't match each other.
Properties are not variables. They are methods, and cannot be passed to ref parameters.
You can't use the ref , in , and out keywords for the following kinds of methods:
Async methods, which you define by using the async modifier.
Iterator methods, which include a yield return or yield break statement.
In addition, extension methods have the following restrictions:
The out keyword cannot be used on the first argument of an extension method.
The ref keyword cannot be used on the first argument of an extension method when the argument is
not a struct, or a generic type not constrained to be a struct.
The in keyword cannot be used unless the first argument is a struct. The in keyword cannot be used
on any generic type, even when constrained to be a struct.
For more information about how to pass reference types by value and by reference, see Passing Reference-
Type Parameters.
Between the return token and the variable returned in a return statement in the method. For example:
The called method may also declare the return value as ref readonly to return the value by reference, and
enforce that the calling code cannot modify the returned value. The calling method can avoid copying the
returned valued by storing the value in a local ref readonly variable.
For an example, see A ref returns and ref locals example.
Ref locals
A ref local variable is used to refer to values returned using return ref . A ref local variable cannot be
initialized to a non-ref return value. In other words, the right-hand side of the initialization must be a
reference. Any modifications to the value of the ref local are reflected in the state of the object whose
method returned the value by reference.
You define a ref local by using the ref keyword before the variable declaration, as well as immediately
before the call to the method that returns the value by reference.
For example, the following statement defines a ref local value that is returned by a method named
GetEstimatedValue :
You can access a value by reference in the same way. In some cases, accessing a value by reference increases
performance by avoiding a potentially expensive copy operation. For example, the following statement
shows how one can define a ref local value that is used to reference a value.
In both examples the ref keyword must be used in both places, or the compiler generates error CS8172,
"Cannot initialize a by-reference variable with a value."
Beginning with C# 7.3, the iteration variable of the foreach statement can be ref local or ref readonly local
variable. For more information, see the foreach statement article.
Also beginning with C# 7.3, you can reassign a ref local or ref readonly local variable with the ref
assignment operator.
When the caller stores the value returned by the GetBookByTitle method as a ref local, changes that the
caller makes to the return value are reflected in the BookCollection object, as the following example shows.
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source
for C# syntax and usage.
See also
Write safe efficient code
Ref returns and ref locals
Conditional ref expression
Passing Parameters
Method Parameters
C# Reference
C# Programming Guide
C# Keywords
out parameter modifier (C# Reference)
9/3/2020 • 4 minutes to read • Edit Online
The out keyword causes arguments to be passed by reference. It makes the formal parameter an alias for
the argument, which must be a variable. In other words, any operation on the parameter is made on the
argument. It is like the ref keyword, except that ref requires that the variable be initialized before it is
passed. It is also like the in keyword, except that in does not allow the called method to modify the
argument value. To use an out parameter, both the method definition and the calling method must explicitly
use the out keyword. For example:
int initializeInMethod;
OutArgExample(out initializeInMethod);
Console.WriteLine(initializeInMethod); // value is now 44
NOTE
The out keyword can also be used with a generic type parameter to specify that the type parameter is covariant. For
more information on the use of the out keyword in this context, see out (Generic Modifier).
Variables passed as out arguments do not have to be initialized before being passed in a method call.
However, the called method is required to assign a value before the method returns.
The in , ref , and out keywords are not considered part of the method signature for the purpose of
overload resolution. Therefore, methods cannot be overloaded if the only difference is that one method takes
a ref or in argument and the other takes an out argument. The following code, for example, will not
compile:
class CS0663_Example
{
// Compiler error CS0663: "Cannot define overloaded
// methods that differ only on ref and out".
public void SampleMethod(out int i) { }
public void SampleMethod(ref int i) { }
}
Overloading is legal, however, if one method takes a ref , in , or out argument and the other has none of
those modifiers, like this:
class OutOverloadExample
{
public void SampleMethod(int i) { }
public void SampleMethod(out int i) => i = 5;
}
The compiler chooses the best overload by matching the parameter modifiers at the call site to the
parameter modifiers used in the method call.
Properties are not variables and therefore cannot be passed as out parameters.
You can't use the in , ref , and out keywords for the following kinds of methods:
Async methods, which you define by using the async modifier.
Iterator methods, which include a yield return or yield break statement.
In addition, extension methods have the following restrictions:
The out keyword cannot be used on the first argument of an extension method.
The ref keyword cannot be used on the first argument of an extension method when the argument is
not a struct, or a generic type not constrained to be a struct.
The in keyword cannot be used unless the first argument is a struct. The in keyword cannot be used
on any generic type, even when constrained to be a struct.
void Method(out int answer, out string message, out string stillNull)
{
answer = 44;
message = "I've been returned";
stillNull = null;
}
int argNumber;
string argMessage, argDefault;
Method(out argNumber, out argMessage, out argDefault);
Console.WriteLine(argNumber);
Console.WriteLine(argMessage);
Console.WriteLine(argDefault == null);
int number;
if (Int32.TryParse(numberAsString, out number))
Console.WriteLine($"Converted '{numberAsString}' to {number}");
else
Console.WriteLine($"Unable to convert '{numberAsString}'");
// The example displays the following output:
// Converted '1640' to 1640
Starting with C# 7.0, you can declare the out variable in the argument list of the method call, rather than in
a separate variable declaration. This produces more compact, readable code, and also prevents you from
inadvertently assigning a value to the variable before the method call. The following example is like the
previous example, except that it defines the number variable in the call to the Int32.TryParse method.
In the previous example, the number variable is strongly typed as an int . You can also declare an implicitly
typed local variable, as the following example does.
C# Language Specification
For more information, see the C# Language Specification. The language specification is the definitive source
for C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
Method Parameters
namespace (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The namespace keyword is used to declare a scope that contains a set of related objects. You can use a namespace
to organize code elements and to create globally unique types.
namespace SampleNamespace
{
class SampleClass { }
interface ISampleInterface { }
struct SampleStruct { }
enum SampleEnum { a, b }
namespace Nested
{
class SampleClass2 { }
}
}
Remarks
Within a namespace, you can declare zero or more of the following types:
another namespace
class
interface
struct
enum
delegate
Whether or not you explicitly declare a namespace in a C# source file, the compiler adds a default namespace. This
unnamed namespace, sometimes referred to as the global namespace, is present in every file. Any identifier in the
global namespace is available for use in a named namespace.
Namespaces implicitly have public access and this is not modifiable. For a discussion of the access modifiers you
can assign to elements in a namespace, see Access Modifiers.
It is possible to define a namespace in two or more declarations. For example, the following example defines two
classes as part of the MyCompany namespace:
namespace MyCompany.Proj1
{
class MyClass
{
}
}
namespace MyCompany.Proj1
{
class MyClass1
{
}
}
Example
The following example shows how to call a static method in a nested namespace.
namespace SomeNameSpace
{
public class MyClass
{
static void Main()
{
Nested.NestedNameSpaceClass.SayHello();
}
}
// a nested namespace
namespace Nested
{
public class NestedNameSpaceClass
{
public static void SayHello()
{
Console.WriteLine("Hello");
}
}
}
}
// Output: Hello
C# language specification
For more information, see the Namespaces section of the C# language specification.
See also
C# reference
C# keywords
using
using static
Namespace alias qualifier ::
Namespaces
using (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
See also
C# Reference
C# Programming Guide
C# Keywords
Namespaces
extern
using directive (C# Reference)
9/3/2020 • 3 minutes to read • Edit Online
using System.Text;
To allow you to access static members and nested types of a type without having to qualify the access
with the type name.
The using keyword is also used to create using statements, which help ensure that IDisposable objects such as
files and fonts are handled correctly. See using Statement for more information.
Remarks
The scope of a using directive is limited to the file in which it appears.
The using directive can appear:
At the beginning of a source code file, before any namespace or type definitions.
In any namespace, but before any namespace or types declared in this namespace.
Otherwise, compiler error CS1529 is generated.
Create a using alias directive to make it easier to qualify an identifier to a namespace or type. In any using
directive, the fully-qualified namespace or type must be used regardless of the using directives that come
before it. No using alias can be used in the declaration of a using directive. For example, the following
generates a compiler error:
using s = System.Text;
using s.RegularExpressions; // Generates a compiler error.
Create a using directive to use the types in a namespace without having to specify the namespace. A using
directive does not give you access to any namespaces that are nested in the namespace you specify.
Namespaces come in two categories: user-defined and system-defined. User-defined namespaces are
namespaces defined in your code. For a list of the system-defined namespaces, see .NET API Browser.
Example 1
The following example shows how to define and use a using alias for a namespace:
namespace PC
{
// Define an alias for the nested namespace.
using Project = PC.MyCompany.Project;
class A
{
void M()
{
// Use the alias
var mc = new Project.MyClass();
}
}
namespace MyCompany
{
namespace Project
{
public class MyClass { }
}
}
}
A using alias directive cannot have an open generic type on the right hand side. For example, you cannot create
a using alias for a List<T> , but you can create one for a List<int> .
Example 2
The following example shows how to define a using directive and a using alias for a class:
using System;
namespace NameSpace1
{
public class MyClass
{
public override string ToString()
{
return "You are in NameSpace1.MyClass.";
}
}
}
namespace NameSpace2
{
class MyClass<T>
{
public override string ToString()
{
return "You are in NameSpace2.MyClass.";
}
}
}
namespace NameSpace3
{
class MainClass
{
static void Main()
{
var instance1 = new AliasToMyClass();
Console.WriteLine(instance1);
C# language specification
For more information, see Using directives in the C# Language Specification. The language specification is the
definitive source for C# syntax and usage.
See also
C# Reference
C# Programming Guide
Using Namespaces
C# Keywords
Namespaces
using Statement
using static directive (C# Reference)
9/3/2020 • 3 minutes to read • Edit Online
The using static directive designates a type whose static members and nested types you can access without
specifying a type name. Its syntax is:
where fully-qualified-type-name is the name of the type whose static members and nested types can be
referenced without specifying a type name. If you do not provide a fully qualified type name (the full namespace
name along with the type name), C# generates compiler error CS0246: "The type or namespace name
'type/namespace' could not be found (are you missing a using directive or an assembly reference?)".
The using static directive applies to any type that has static members (or nested types), even if it also has
instance members. However, instance members can only be invoked through the type instance.
The using static directive was introduced in C# 6.
Remarks
Ordinarily, when you call a static member, you provide the type name along with the member name. Repeatedly
entering the same type name to invoke members of the type can result in verbose, obscure code. For example, the
following definition of a Circle class references a number of members of the Math class.
using System;
By eliminating the need to explicitly reference the Math class each time a member is referenced, the using static
directive produces much cleaner code:
using System;
using static System.Math;
using static imports only accessible static members and nested types declared in the specified type. Inherited
members are not imported. You can import from any named type with a using static directive, including Visual
Basic modules. If F# top-level functions appear in metadata as static members of a named type whose name is a
valid C# identifier, then the F# functions can be imported.
using static makes extension methods declared in the specified type available for extension method lookup.
However, the names of the extension methods are not imported into scope for unqualified reference in code.
Methods with the same name imported from different types by different using static directives in the same
compilation unit or namespace form a method group. Overload resolution within these method groups follows
normal C# rules.
Example
The following example uses the using static directive to make the static members of the Console, Math, and
String classes available without having to specify their type name.
using System;
using static System.Console;
using static System.Math;
using static System.String;
class Program
{
static void Main()
{
Write("Enter a circle's radius: ");
var input = ReadLine();
if (!IsNullOrEmpty(input) && double.TryParse(input, out var radius)) {
var c = new Circle(radius);
In the example, the using static directive could also have been applied to the Double type. This would have
made it possible to call the TryParse(String, Double) method without specifying a type name. However, this creates
less readable code, since it becomes necessary to check the using static directives to determine which numeric
type's TryParse method is called.
See also
using directive
C# Reference
C# Keywords
Using Namespaces
Namespaces
using statement (C# Reference)
9/3/2020 • 4 minutes to read • Edit Online
Provides a convenient syntax that ensures the correct use of IDisposable objects. Beginning in C# 8.0, the
using statement ensures the correct use of IAsyncDisposable objects.
Example
The following example shows how to use the using statement.
Beginning with C# 8.0, you can use the following alternative syntax for the using statement that doesn't
require braces:
Remarks
File and Font are examples of managed types that access unmanaged resources (in this case file handles and
device contexts). There are many other kinds of unmanaged resources and class library types that encapsulate
them. All such types must implement the IDisposable interface, or the IAsyncDisposable interface.
When the lifetime of an IDisposable object is limited to a single method, you should declare and instantiate it
in the using statement. The using statement calls the Dispose method on the object in the correct way, and
(when you use it as shown earlier) it also causes the object itself to go out of scope as soon as Dispose is called.
Within the using block, the object is read-only and can't be modified or reassigned. If the object implements
IAsyncDisposable instead of IDisposable , the using statement calls the DisposeAsync and awaits the
returned ValueTask. For more information on IAsyncDisposable, see Implement a DisposeAsync method.
The usingstatement ensures that Dispose (or DisposeAsync) is called even if an exception occurs within the
using block. You can achieve the same result by putting the object inside a try block and then calling Dispose
(or DisposeAsync) in a finally block; in fact, this is how the using statement is translated by the compiler.
The code example earlier expands to the following code at compile time (note the extra curly braces to create
the limited scope for the object):
{
var reader = new StringReader(manyLines);
try {
string? item;
do {
item = reader.ReadLine();
Console.WriteLine(item);
} while(item != null);
} finally
{
reader?.Dispose();
}
}
The newer using statement syntax translates to similar code. The try block opens where the variable is
declared. The finally block is added at the close of the enclosing block, typically at the end of a method.
For more information about the try - finally statement, see the try-finally article.
Multiple instances of a type can be declared in a single using statement, as shown in the following example.
Notice that you can't use implicitly typed variables ( var ) when you declare multiple variables in a single
statement:
string numbers=@"One
Two
Three
Four.";
string letters=@"A
B
C
D.";
You can combine multiple declarations of the same type using the new syntax introduced with C# 8 as well, as
shown in the following example:
string numbers=@"One
Two
Three
Four.";
string letters=@"A
B
C
D.";
You can instantiate the resource object and then pass the variable to the using statement, but this isn't a best
practice. In this case, after control leaves the using block, the object remains in scope but probably has no
access to its unmanaged resources. In other words, it's not fully initialized anymore. If you try to use the object
outside the using block, you risk causing an exception to be thrown. For this reason, it's better to instantiate
the object in the using statement and limit its scope to the using block.
For more information about disposing of IDisposable objects, see Using objects that implement IDisposable.
C# language specification
For more information, see The using statement in the C# Language Specification. The language specification is
the definitive source for C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
using Directive
Garbage Collection
Using objects that implement IDisposable
IDisposable interface
using statement in C# 8.0
extern alias (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
You might have to reference two versions of assemblies that have the same fully-qualified type names. For
example, you might have to use two or more versions of an assembly in the same application. By using an external
assembly alias, the namespaces from each assembly can be wrapped inside root-level namespaces named by the
alias, which enables them to be used in the same file.
NOTE
The extern keyword is also used as a method modifier, declaring a method written in unmanaged code.
To reference two assemblies with the same fully-qualified type names, an alias must be specified at a command
prompt, as follows:
/r:GridV1=grid.dll
/r:GridV2=grid20.dll
This creates the external aliases GridV1 and GridV2 . To use these aliases from within a program, reference them
by using the extern keyword. For example:
extern alias GridV1;
Each extern alias declaration introduces an additional root-level namespace that parallels (but does not lie within)
the global namespace. Thus types from each assembly can be referred to without ambiguity by using their fully
qualified name, rooted in the appropriate namespace-alias.
In the previous example, GridV1::Grid would be the grid control from grid.dll , and GridV2::Grid would be the
grid control from grid20.dll .
Now you can create alias for a namespace or a type by using alias directive. For more information, see using
directive.
See also
C# Reference
C# Programming Guide
C# Keywords
:: Operator
-reference (C# Compiler Options)
is (C# Reference)
9/3/2020 • 7 minutes to read • Edit Online
The is operator checks if the result of an expression is compatible with a given type, or (starting with C# 7.0)
tests an expression against a pattern. For information about the type-testing is operator see the is operator
section of the Type-testing and cast operators article.
Where expr is an expression that evaluates to an instance of some type, type is the name of the type to which the
result of expr is to be converted, and varname is the object to which the result of expr is converted if the is test
is true .
The is expression is true if expr isn't null , and any of the following is true:
expr is an instance of the same type as type.
expr is an instance of a type that derives from type. In other words, the result of expr can be upcast to an
instance of type.
expr has a compile-time type that is a base class of type, and expr has a runtime type that is type or is
derived from type. The compile-time type of a variable is the variable's type as defined in its declaration.
The runtime type of a variable is the type of the instance that is assigned to that variable.
expr is an instance of a type that implements the type interface.
Beginning with C# 7.1, expr may have a compile-time type defined by a generic type parameter and its
constraints.
If expr is true and is is used with an if statement, varname is assigned within the if statement only. The
scope of varname is from the is expression to the end of the block enclosing the if statement. Using varname
in any other location generates a compile-time error for use of a variable that has not been assigned.
The following example uses the is type pattern to provide the implementation of a type's
IComparable.CompareTo(Object) method.
using System;
Without pattern matching, this code might be written as follows. The use of type pattern matching produces more
compact, readable code by eliminating the need to test whether the result of a conversion is a null .
using System;
The is type pattern also produces more compact code when determining the type of a value type. The following
example uses the is type pattern to determine whether an object is a Person or a Dog instance before
displaying the value of an appropriate property.
using System;
The equivalent code without pattern matching requires a separate assignment that includes an explicit cast.
using System;
Constant pattern
When performing pattern matching with the constant pattern, is tests whether an expression equals a specified
constant. In C# 6 and earlier versions, the constant pattern is supported by the switch statement. Starting with C#
7.0, it's supported by the is statement as well. Its syntax is:
expr is constant
where expr is the expression to evaluate, and constant is the value to test for. constant can be any of the following
constant expressions:
A literal value.
The name of a declared const variable.
An enumeration constant.
The constant expression is evaluated as follows:
If expr and constant are integral types, the C# equality operator determines whether the expression returns
true (that is, whether expr == constant ).
Otherwise, the value of the expression is determined by a call to the static Object.Equals(expr, constant)
method.
The following example combines the type and constant patterns to test whether an object is a Dice instance and,
if it is, to determine whether the value of a dice roll is 6.
using System;
class Program
{
static void Main(string[] args)
{
var d1 = new Dice();
ShowValue(d1);
}
Checking for null can be performed using the constant pattern. The null keyword is supported by the is
statement. Its syntax is:
expr is null
class Program
{
static void Main(string[] args)
{
object o = null;
if (o is null)
{
Console.WriteLine("o does not have a value");
}
else
{
Console.WriteLine($"o is {o}");
}
int? x = 10;
if (x is null)
{
Console.WriteLine("x does not have a value");
}
else
{
Console.WriteLine($"x is {x.Value}");
}
var pattern
A pattern match with the var pattern always succeeds. Its syntax is:
Where the value of expr is always assigned to a local variable named varname. varname is a variable of the same
type as the compile-time type of expr.
If expr evaluates to null , the is expression produces true and assigns null to varname. The var pattern is
one of the few uses of is that produces true for a null value.
You can use the var pattern to create a temporary variable within a Boolean expression, as the following
example shows:
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
int[] testSet = { 100271, 234335, 342439, 999683 };
In the preceding example, the temporary variable is used to store the result of an expensive operation. The
variable can then be used multiple times.
C# language specification
For more information, see The is operator section of the C# language specification and the following C# language
proposals:
Pattern matching
Pattern matching with generics
See also
C# reference
C# keywords
Type-testing and cast operators
new constraint (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The new constraint specifies that a type argument in a generic class declaration must have a public parameterless
constructor. To use the new constraint, the type cannot be abstract.
Apply the new constraint to a type parameter when a generic class creates new instances of the type, as shown in
the following example:
When you use the new() constraint with other constraints, it must be specified last:
C# language specification
For more information, see the Type parameter constraints section of the C# language specification.
See also
C# Reference
C# Programming Guide
C# Keywords
Generics
where (generic type constraint) (C# Reference)
9/3/2020 • 4 minutes to read • Edit Online
The where clause in a generic definition specifies constraints on the types that are used as arguments for type
parameters in a generic type, method, delegate, or local function. Constraints can specify interfaces, base classes,
or require a generic type to be a reference, value, or unmanaged type. They declare capabilities that the type
argument must have.
For example, you can declare a generic class, MyGenericClass , such that the type parameter T implements the
IComparable<T> interface:
NOTE
For more information on the where clause in a query expression, see where clause.
The where clause can also include a base class constraint. The base class constraint states that a type to be used as
a type argument for that generic type has the specified class as a base class, or is that base class. If the base class
constraint is used, it must appear before any other constraints on that type parameter. Some types are disallowed
as a base class constraint: Object, Array, and ValueType. Before C# 7.3, Enum, Delegate, and MulticastDelegate were
also disallowed as base class constraints. The following example shows the types that can now be specified as a
base class:
In a nullable context in C# 8.0 and later, the nullability of the base class type is enforced. If the base class is non-
nullable (for example Base ), the type argument must be non-nullable. If the base class is nullable (for example
Base? ), the type argument may be either a nullable or non-nullable reference type. The compiler issues a warning
if the type argument is a nullable reference type when the base class is non-nullable.
The where clause can specify that the type is a class or a struct . The struct constraint removes the need to
specify a base class constraint of System.ValueType . The System.ValueType type may not be used as a base class
constraint. The following example shows both the class and struct constraints:
In a nullable context in C# 8.0 and later, the class constraint requires a type to be a non-nullable reference type.
To allow nullable reference types, use the class? constraint, which allows both nullable and non-nullable
reference types.
The where clause may include the notnull constraint. The notnull constraint limits the type parameter to non-
nullable types. That type may be a value type or a non-nullable reference type. The notnull constraint is available
starting in C# 8.0 for code compiled in a nullable enable context. Unlike other constraints, if a type argument
violates the notnull constraint, the compiler generates a warning instead of an error. Warnings are only
generated in a nullable enable context.
IMPORTANT
Generic declarations that include the notnull constraint can be used in a nullable oblivious context, but compiler does not
enforce the constraint.
#nullable enable
class NotNullContainer<T>
where T : notnull
{
}
#nullable restore
The where clause may also include an unmanaged constraint. The unmanaged constraint limits the type parameter
to types known as unmanaged types. The unmanaged constraint makes it easier to write low-level interop code in
C#. This constraint enables reusable routines across all unmanaged types. The unmanaged constraint can't be
combined with the class or struct constraint. The unmanaged constraint enforces that the type must be a
struct :
class UnManagedWrapper<T>
where T : unmanaged
{ }
The where clause may also include a constructor constraint, new() . That constraint makes it possible to create an
instance of a type parameter using the new operator. The new() Constraint lets the compiler know that any type
argument supplied must have an accessible parameterless constructor. For example:
The new() constraint appears last in the where clause. The new() constraint can't be combined with the struct
or unmanaged constraints. All types satisfying those constraints must have an accessible parameterless constructor,
making the new() constraint redundant.
With multiple type parameters, use one where clause for each type parameter, for example:
namespace CodeExample
{
class Dictionary<TKey, TVal>
where TKey : IComparable<TKey>
where TVal : IMyInterface
{
public void Add(TKey key, TVal val) { }
}
}
You can also attach constraints to type parameters of generic methods, as shown in the following example:
Notice that the syntax to describe type parameter constraints on delegates is the same as that of methods:
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for C#
syntax and usage.
See also
C# Reference
C# Programming Guide
Introduction to Generics
new Constraint
Constraints on Type Parameters
base (C# Reference)
1/7/2020 • 2 minutes to read • Edit Online
The base keyword is used to access members of the base class from within a derived class:
Call a method on the base class that has been overridden by another method.
Specify which base-class constructor should be called when creating instances of the derived class.
A base class access is permitted only in a constructor, an instance method, or an instance property accessor.
It is an error to use the base keyword from within a static method.
The base class that is accessed is the base class specified in the class declaration. For example, if you specify
class ClassB : ClassA , the members of ClassA are accessed from ClassB, regardless of the base class of ClassA.
Example
In this example, both the base class, Person , and the derived class, Employee , have a method named Getinfo .
By using the base keyword, it is possible to call the Getinfo method on the base class, from within the derived
class.
public class Person
{
protected string ssn = "444-55-6666";
protected string name = "John L. Malgraine";
class TestClass
{
static void Main()
{
Employee E = new Employee();
E.GetInfo();
}
}
/*
Output
Name: John L. Malgraine
SSN: 444-55-6666
Employee ID: ABC567EFG
*/
Example
This example shows how to specify the base-class constructor called when creating instances of a derived class.
public class BaseClass
{
int num;
public BaseClass()
{
Console.WriteLine("in BaseClass()");
}
public BaseClass(int i)
{
num = i;
Console.WriteLine("in BaseClass(int i)");
}
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
this
this (C# Reference)
1/7/2020 • 2 minutes to read • Edit Online
The this keyword refers to the current instance of the class and is also used as a modifier of the first parameter
of an extension method.
NOTE
This article discusses the use of this with class instances. For more information about its use in extension methods, see
Extension Methods.
CalcTax(this);
Static member functions, because they exist at the class level and not as part of an object, do not have a this
pointer. It is an error to refer to this in a static method.
Example
In this example, this is used to qualify the Employee class members, name and alias , which are hidden by
similar names. It is also used to pass an object to the method CalcTax , which belongs to another class.
class Employee
{
private string name;
private string alias;
private decimal salary = 3000.00m;
// Constructor:
public Employee(string name, string alias)
{
// Use this to qualify the fields, name and alias:
this.name = name;
this.alias = alias;
}
// Printing method:
public void printEmployee()
{
Console.WriteLine("Name: {0}\nAlias: {1}", name, alias);
// Passing the object to the CalcTax method by using this:
Console.WriteLine("Taxes: {0:C}", Tax.CalcTax(this));
}
class Tax
{
public static decimal CalcTax(Employee E)
{
return 0.08m * E.Salary;
}
}
class MainClass
{
static void Main()
{
// Create objects:
Employee E1 = new Employee("Mingda Pan", "mpan");
// Display results:
E1.printEmployee();
}
}
/*
Output:
Name: Mingda Pan
Alias: mpan
Taxes: $240.00
*/
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
base
Methods
null (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The null keyword is a literal that represents a null reference, one that does not refer to any object. null is the
default value of reference-type variables. Ordinary value types cannot be null, except for nullable value types.
The following example demonstrates some behaviors of the null keyword:
class Program
{
class MyClass
{
public void MyMethod() { }
}
// Returns true.
Console.WriteLine("null == null is {0}", null == null);
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# reference
C# keywords
Default values of C# types
Nothing (Visual Basic)
bool (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
The bool type keyword is an alias for the .NET System.Boolean structure type that represents a Boolean
value, which can be either true or false .
To perform logical operations with values of the bool type, use Boolean logical operators. The bool type is
the result type of comparison and equality operators. A bool expression can be a controlling conditional
expression in the if, do, while, and for statements and in the conditional operator ?: .
The default value of the bool type is false .
Literals
You can use the true and false literals to initialize a bool variable or to pass a bool value:
Conversions
C# provides only two conversions that involve the bool type. Those are an implicit conversion to the
corresponding nullable bool? type and an explicit conversion from the bool? type. However, .NET provides
additional methods that you can use to convert to or from the bool type. For more information, see the
Converting to and from Boolean values section of the System.Boolean API reference page.
C# language specification
For more information, see The bool type section of the C# language specification.
See also
C# reference
Value types
true and false operators
default (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
See also
C# Reference
C# Programming Guide
C# Keywords
Contextual Keywords (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
A contextual keyword is used to provide a specific meaning in the code, but it is not a reserved word in C#. The
following contextual keywords are introduced in this section:
K EY W O RD DESC RIP T IO N
All query keywords introduced in C# 3.0 are also contextual. For more information, see Query Keywords (LINQ).
See also
C# Reference
C# Programming Guide
C# Keywords
add (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The add contextual keyword is used to define a custom event accessor that is invoked when client code
subscribes to your event. If you supply a custom add accessor, you must also supply a remove accessor.
Example
The following example shows an event that has custom add and remove accessors. For the full example, see How
to implement interface events.
You do not typically need to provide your own custom event accessors. The accessors that are automatically
generated by the compiler when you declare an event are sufficient for most scenarios.
See also
Events
get (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The get keyword defines an accessor method in a property or indexer that returns the property value or the
indexer element. For more information, see Properties, Auto-Implemented Properties and Indexers.
The following example defines both a get and a set accessor for a property named Seconds . It uses a
private field named _seconds to back the property value.
class TimePeriod
{
private double _seconds;
Often, the get accessor consists of a single statement that returns a value, as it did in the previous example.
Starting with C# 7.0, you can implement the get accessor as an expression-bodied member. The following
example implements both the get and the set accessor as expression-bodied members.
class TimePeriod
{
private double _seconds;
For simple cases in which a property's get and set accessors perform no other operation than setting or
retrieving a value in a private backing field, you can take advantage of the C# compiler's support for auto-
implemented properties. The following example implements Hours as an auto-implemented property.
class TimePeriod2
{
public double Hours { get; set; }
}
C# Language Specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
Properties
partial type (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
Partial type definitions allow for the definition of a class, struct, or interface to be split into multiple files.
In File1.cs:
namespace PC
{
partial class A
{
int num = 0;
void MethodA() { }
partial void MethodC();
}
}
namespace PC
{
partial class A
{
void MethodB() { }
partial void MethodC() { }
}
}
Remarks
Splitting a class, struct or interface type over several files can be useful when you are working with large projects,
or with automatically generated code such as that provided by the Windows Forms Designer. A partial type may
contain a partial method. For more information, see Partial Classes and Methods.
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Reference
C# Programming Guide
Modifiers
Introduction to Generics
partial method (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
A partial method has its signature defined in one part of a partial type, and its implementation defined in another
part of the type. Partial methods enable class designers to provide method hooks, similar to event handlers, that
developers may decide to implement or not. If the developer does not supply an implementation, the compiler
removes the signature at compile time. The following conditions apply to partial methods:
Signatures in both parts of the partial type must match.
The method must return void.
No access modifiers are allowed. Partial methods are implicitly private.
The following example shows a partial method defined in two parts of a partial class:
namespace PM
{
partial class A
{
partial void OnSomethingHappened(string s);
}
See also
C# Reference
partial type
remove (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The remove contextual keyword is used to define a custom event accessor that is invoked when client code
unsubscribes from your event. If you supply a custom remove accessor, you must also supply an add accessor.
Example
The following example shows an event with custom add and remove accessors. For the full example, see How to
implement interface events.
You do not typically need to provide your own custom event accessors. The accessors that are automatically
generated by the compiler when you declare an event are sufficient for most scenarios.
See also
Events
set (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The set keyword defines an accessor method in a property or indexer that assigns a value to the property or
the indexer element. For more information and examples, see Properties, Auto-Implemented Properties, and
Indexers.
The following example defines both a get and a set accessor for a property named Seconds . It uses a private
field named _seconds to back the property value.
class TimePeriod
{
private double _seconds;
Often, the set accessor consists of a single statement that assigns a value, as it did in the previous example.
Starting with C# 7.0, you can implement the set accessor as an expression-bodied member. The following
example implements both the get and the set accessors as expression-bodied members.
class TimePeriod
{
private double _seconds;
For simple cases in which a property's get and set accessors perform no other operation than setting or
retrieving a value in a private backing field, you can take advantage of the C# compiler's support for auto-
implemented properties. The following example implements Hours as an auto-implemented property.
class TimePeriod2
{
public double Hours { get; set; }
}
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
Properties
when (C# Reference)
9/3/2020 • 3 minutes to read • Edit Online
You can use the when contextual keyword to specify a filter condition in the following contexts:
In the catch statement of a try/catch or try/catch/finally block.
In the case label of a switch statement.
In the switch expression.
where expr is an expression that evaluates to a Boolean value. If it returns true , the exception handler executes; if
false , it does not.
The following example uses the when keyword to conditionally execute handlers for an HttpRequestException
depending on the text of the exception message.
using System;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
static void Main()
{
Console.WriteLine(MakeRequest().Result);
}
where expr is a constant pattern or type pattern that is compared to the match expression, and when-condition is
any Boolean expression.
The following example uses the when keyword to test for Shape objects that have an area of zero, as well as to
test for a variety of Shape objects that have an area greater than zero.
using System;
See also
switch statement
try/catch statement
try/catch/finally statement
value (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The contextual keyword value is used in the set accessor in property and indexer declarations. It is similar to an
input parameter of a method. The word value references the value that client code is attempting to assign to the
property or indexer. In the following example, MyDerivedClass has a property called Name that uses the value
parameter to assign a new string to the backing field name . From the point of view of client code, the operation is
written as a simple assignment.
class MyBaseClass
{
// virtual auto-implemented property. Overrides can only
// provide specialized behavior if they implement get and set accessors.
public virtual string Name { get; set; }
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for
C# syntax and usage.
See also
C# Reference
C# Programming Guide
C# Keywords
yield (C# Reference)
9/3/2020 • 4 minutes to read • Edit Online
When you use the yield contextual keyword in a statement, you indicate that the method, operator, or get
accessor in which it appears is an iterator. Using yield to define an iterator removes the need for an explicit
extra class (the class that holds the state for an enumeration, see IEnumerator<T> for an example) when you
implement the IEnumerable and IEnumerator pattern for a custom collection type.
The following example shows the two forms of the yield statement.
Remarks
You use a yield return statement to return each element one at a time.
The sequence returned from an iterator method can be consumed by using a foreach statement or LINQ
query. Each iteration of the foreach loop calls the iterator method. When a yield return statement is
reached in the iterator method, expression is returned, and the current location in code is retained. Execution
is restarted from that location the next time that the iterator function is called.
You can use a yield break statement to end the iteration.
For more information about iterators, see Iterators.
Exception handling
A yield return statement can't be located in a try-catch block. A yield return statement can be located in
the try block of a try-finally statement.
A yield break statement can be located in a try block or a catch block but not a finally block.
If the foreach body (outside of the iterator method) throws an exception, a finally block in the iterator
method is executed.
Technical implementation
The following code returns an IEnumerable<string> from an iterator method and then iterates through its
elements.
The call to MyIteratorMethod doesn't execute the body of the method. Instead the call returns an
IEnumerable<string> into the elements variable.
On an iteration of the foreach loop, the MoveNext method is called for elements . This call executes the body
of MyIteratorMethod until the next yield return statement is reached. The expression returned by the
yield return statement determines not only the value of the element variable for consumption by the loop
body but also the Current property of elements , which is an IEnumerable<string> .
On each subsequent iteration of the foreach loop, the execution of the iterator body continues from where it
left off, again stopping when it reaches a yield return statement. The foreach loop completes when the end
of the iterator method or a yield break statement is reached.
Example
The following example has a yield return statement that's inside a for loop. Each iteration of the foreach
statement body in the Main method creates a call to the Power iterator function. Each call to the iterator
function proceeds to the next execution of the yield return statement, which occurs during the next iteration
of the for loop.
The return type of the iterator method is IEnumerable, which is an iterator interface type. When the iterator
method is called, it returns an enumerable object that contains the powers of a number.
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source
for C# syntax and usage.
See also
C# Reference
C# Programming Guide
foreach, in
Iterators
Query keywords (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
In this section
C L A USE DESC RIP T IO N
select Specifies the type and shape that the elements in the
returned sequence will have when the query is executed.
See also
C# Keywords
LINQ (Language-Integrated Query)
LINQ in C#
from clause (C# Reference)
9/3/2020 • 5 minutes to read • Edit Online
A query expression must begin with a from clause. Additionally, a query expression can contain sub-queries,
which also begin with a from clause. The from clause specifies the following:
The data source on which the query or sub-query will be run.
A local range variable that represents each element in the source sequence.
Both the range variable and the data source are strongly typed. The data source referenced in the from clause
must have a type of IEnumerable, IEnumerable<T>, or a derived type such as IQueryable<T>.
In the following example, numbers is the data source and num is the range variable. Note that both variables are
strongly typed even though the var keyword is used.
class LowNums
{
static void Main()
{
// A simple data source.
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
// Use a compound from to access the inner sequence within each element.
// Note the similarity to a nested foreach statement.
var scoreQuery = from student in students
from score in student.Scores
where score > 90
select new { Last = student.LastName, score };
Console.WriteLine("Filtered non-equijoin:");
// Rest the mouse pointer over joinQuery2 to verify its type.
foreach (var pair in joinQuery2)
{
Console.WriteLine("{0} is matched to {1}", pair.lower, pair.upper);
}
For more information about join operations that use multiple from clauses, see Perform left outer joins.
See also
Query Keywords (LINQ)
Language Integrated Query (LINQ)
where clause (C# Reference)
9/3/2020 • 3 minutes to read • Edit Online
The where clause is used in a query expression to specify which elements from the data source will be
returned in the query expression. It applies a Boolean condition (predicate) to each source element (referenced
by the range variable) and returns those for which the specified condition is true. A single query expression
may contain multiple where clauses and a single clause may contain multiple predicate subexpressions.
Example
In the following example, the where clause filters out all numbers except those that are less than five. If you
remove the where clause, all numbers from the data source would be returned. The expression num < 5 is the
predicate that is applied to each element.
class WhereSample
{
static void Main()
{
// Simple data source. Arrays support IEnumerable<T>.
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
Example
Within a single where clause, you can specify as many predicates as necessary by using the && and ||
operators. In the following example, the query specifies two predicates in order to select only the even numbers
that are less than five.
class WhereSample2
{
static void Main()
{
// Data source.
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
Example
A where clause may contain one or more methods that return Boolean values. In the following example, the
where clause uses a method to determine whether the current value of the range variable is even or odd.
class WhereSample3
{
static void Main()
{
// Data source
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
Remarks
The where clause is a filtering mechanism. It can be positioned almost anywhere in a query expression, except
it cannot be the first or last clause. A where clause may appear either before or after a group clause depending
on whether you have to filter the source elements before or after they are grouped.
If a specified predicate is not valid for the elements in the data source, a compile-time error will result. This is
one benefit of the strong type-checking provided by LINQ.
At compile time the where keyword is converted into a call to the Where Standard Query Operator method.
See also
Query Keywords (LINQ)
from clause
select clause
Filtering Data
LINQ in C#
Language Integrated Query (LINQ)
select clause (C# Reference)
9/3/2020 • 6 minutes to read • Edit Online
In a query expression, the select clause specifies the type of values that will be produced when the query is
executed. The result is based on the evaluation of all the previous clauses and on any expressions in the
select clause itself. A query expression must terminate with either a select clause or a group clause.
class SelectSample1
{
static void Main()
{
//Create the data source
List<int> Scores = new List<int>() { 97, 92, 81, 60 };
The type of the sequence produced by the select clause determines the type of the query variable
queryHighScores . In the simplest case, the select clause just specifies the range variable. This causes the
returned sequence to contain elements of the same type as the data source. For more information, see Type
Relationships in LINQ Query Operations. However, the select clause also provides a powerful mechanism for
transforming (or projecting) source data into new types. For more information, see Data Transformations with
LINQ (C#).
Example
The following example shows all the different forms that a select clause may take. In each query, note the
relationship between the select clause and the type of the query variable ( studentQuery1 , studentQuery2 ,
and so on).
class SelectSample2
{
// Define some classes
public class Student
{
public string First { get; set; }
public string Last { get; set; }
public int ID { get; set; }
public List<int> Scores;
public ContactInfo GetContactInfo(SelectSample2 app, int id)
{
ContactInfo cInfo =
(from ci in app.contactList
where ci.ID == id
select ci)
.FirstOrDefault();
return cInfo;
}
As shown in studentQuery8 in the previous example, sometimes you might want the elements of the returned
sequence to contain only a subset of the properties of the source elements. By keeping the returned sequence
as small as possible you can reduce the memory requirements and increase the speed of the execution of the
query. You can accomplish this by creating an anonymous type in the select clause and using an object
initializer to initialize it with the appropriate properties from the source element. For an example of how to do
this, see Object and Collection Initializers.
Remarks
At compile time, the select clause is translated to a method call to the Select standard query operator.
See also
C# Reference
Query Keywords (LINQ)
from clause
partial (Method) (C# Reference)
Anonymous Types
LINQ in C#
Language Integrated Query (LINQ)
group clause (C# Reference)
9/3/2020 • 8 minutes to read • Edit Online
The group clause returns a sequence of IGrouping<TKey,TElement> objects that contain zero or more items
that match the key value for the group. For example, you can group a sequence of strings according to the first
letter in each string. In this case, the first letter is the key and has a type char, and is stored in the Key property
of each IGrouping<TKey,TElement> object. The compiler infers the type of the key.
You can end a query expression with a group clause, as shown in the following example:
If you want to perform additional query operations on each group, you can specify a temporary identifier by
using the into contextual keyword. When you use into , you must continue with the query, and eventually end
it with either a select statement or another group clause, as shown in the following excerpt:
More complete examples of the use of group with and without into are provided in the Example section of
this article.
Key types
Group keys can be any type, such as a string, a built-in numeric type, or a user-defined named type or
anonymous type.
Grouping by string
The previous code examples used a char . A string key could easily have been specified instead, for example
the complete last name:
// Same as previous example except we use the entire last name as a key.
// Query variable is an IEnumerable<IGrouping<string, Student>>
var studentQuery3 =
from student in students
group student by student.Last;
Grouping by bool
The following example shows the use of a bool value for a key to divide the results into two groups. Note that
the value is produced by a sub-expression in the group clause.
class GroupSample1
{
// The element type of the data source.
public class Student
{
public string First { get; set; }
public string Last { get; set; }
public int ID { get; set; }
public List<int> Scores;
}
return students;
}
class GroupSample2
{
// The element type of the data source.
public class Student
{
public string First { get; set; }
public string Last { get; set; }
public int ID { get; set; }
public List<int> Scores;
}
return students;
}
Use a named type if you must pass the query variable to another method. Create a special class using auto-
implemented properties for the keys, and then override the Equals and GetHashCode methods. You can also
use a struct, in which case you do not strictly have to override those methods. For more information see How
to implement a lightweight class with auto-implemented properties and How to query for duplicate files in a
directory tree. The latter article has a code example that demonstrates how to use a composite key with a
named type.
Example
The following example shows the standard pattern for ordering source data into groups when no additional
query logic is applied to the groups. This is called a grouping without a continuation. The elements in an array
of strings are grouped according to their first letter. The result of the query is an IGrouping<TKey,TElement>
type that contains a public Key property of type char and an IEnumerable<T> collection that contains each
item in the grouping.
The result of a group clause is a sequence of sequences. Therefore, to access the individual elements within
each returned group, use a nested foreach loop inside the loop that iterates the group keys, as shown in the
following example.
class GroupExample1
{
static void Main()
{
// Create a data source.
string[] words = { "blueberry", "chimpanzee", "abacus", "banana", "apple", "cheese" };
Example
This example shows how to perform additional logic on the groups after you have created them, by using a
continuation with into . For more information, see into. The following example queries each group to select
only those whose key value is a vowel.
class GroupClauseExample2
{
static void Main()
{
// Create the data source.
string[] words2 = { "blueberry", "chimpanzee", "abacus", "banana", "apple", "cheese", "elephant",
"umbrella", "anteater" };
Remarks
At compile time, group clauses are translated into calls to the GroupBy method.
See also
IGrouping<TKey,TElement>
GroupBy
ThenBy
ThenByDescending
Query Keywords
Language Integrated Query (LINQ)
Create a nested group
Group query results
Perform a subquery on a grouping operation
into (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The into contextual keyword can be used to create a temporary identifier to store the results of a group, join or
select clause into a new identifier. This identifier can itself be a generator for additional query commands. When
used in a group or select clause, the use of the new identifier is sometimes referred to as a continuation.
Example
The following example shows the use of the into keyword to enable a temporary identifier fruitGroup which
has an inferred type of IGrouping . By using the identifier, you can invoke the Count method on each group and
select only those groups that contain two or more words.
class IntoSample1
{
static void Main()
{
// Execute the query. Note that we only iterate over the groups,
// not the items in each group
foreach (var item in wordGroups1)
{
Console.WriteLine(" {0} has {1} elements.", item.FirstLetter, item.Words);
}
The use of into in a group clause is only necessary when you want to perform additional query operations on
each group. For more information, see group clause.
For an example of the use of into in a join clause, see join clause.
See also
Query Keywords (LINQ)
LINQ in C#
group clause
orderby clause (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
In a query expression, the orderby clause causes the returned sequence or subsequence (group) to be sorted
in either ascending or descending order. Multiple keys can be specified in order to perform one or more
secondary sort operations. The sorting is performed by the default comparer for the type of the element. The
default sort order is ascending. You can also specify a custom comparer. However, it is only available by using
method-based syntax. For more information, see Sorting Data.
Example
In the following example, the first query sorts the words in alphabetical order starting from A, and second
query sorts the same words in descending order. (The ascending keyword is the default sort value and can be
omitted.)
class OrderbySample1
{
static void Main()
{
// Create a delicious data source.
string[] fruits = { "cherry", "apple", "blueberry" };
Descending:
cherry
blueberry
apple
*/
Example
The following example performs a primary sort on the students' last names, and then a secondary sort on
their first names.
class OrderbySample2
{
// The element type of the data source.
public class Student
{
public string First { get; set; }
public string Last { get; set; }
public int ID { get; set; }
}
public static List<Student> GetStudents()
{
// Use a collection initializer to create the data source. Note that each element
// in the list contains an inner sequence of scores.
List<Student> students = new List<Student>
{
new Student {First="Svetlana", Last="Omelchenko", ID=111},
new Student {First="Claire", Last="O'Donnell", ID=112},
new Student {First="Sven", Last="Mortensen", ID=113},
new Student {First="Cesar", Last="Garcia", ID=114},
new Student {First="Debra", Last="Garcia", ID=115}
};
return students;
}
static void Main(string[] args)
{
// Create the data source.
List<Student> students = GetStudents();
// Now create groups and sort the groups. The query first sorts the names
// of all students so that they will be in alphabetical order after they are
// grouped. The second orderby sorts the group keys in alpha order.
var sortedGroups =
from student in students
orderby student.Last, student.First
group student by student.Last[0] into newGroup
orderby newGroup.Key
select newGroup;
sortedGroups:
G
Garcia, Cesar
Garcia, Debra
Garcia, Debra
M
Mortensen, Sven
O
O'Donnell, Claire
Omelchenko, Svetlana
*/
Remarks
At compile time, the orderby clause is translated to a call to the OrderBy method. Multiple keys in the orderby
clause translate to ThenBy method calls.
See also
C# Reference
Query Keywords (LINQ)
LINQ in C#
group clause
Language Integrated Query (LINQ)
join clause (C# Reference)
9/3/2020 • 9 minutes to read • Edit Online
The join clause is useful for associating elements from different source sequences that have no direct
relationship in the object model. The only requirement is that the elements in each source share some value
that can be compared for equality. For example, a food distributor might have a list of suppliers of a certain
product, and a list of buyers. A join clause can be used, for example, to create a list of the suppliers and
buyers of that product who are all in the same specified region.
A join clause takes two source sequences as input. The elements in each sequence must either be or contain
a property that can be compared to a corresponding property in the other sequence. The join clause
compares the specified keys for equality by using the special equals keyword. All joins performed by the
join clause are equijoins. The shape of the output of a join clause depends on the specific type of join you
are performing. The following are three most common join types:
Inner join
Group join
Left outer join
Inner join
The following example shows a simple inner equijoin. This query produces a flat sequence of "product name /
category" pairs. The same category string will appear in multiple elements. If an element from categories
has no matching products , that category will not appear in the results.
var innerJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID
select new { ProductName = prod.Name, Category = category.Name }; //produces flat sequence
Group join
A join clause with an into expression is called a group join.
var innerGroupJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
select new { CategoryName = category.Name, Products = prodGroup };
A group join produces a hierarchical result sequence, which associates elements in the left source sequence
with one or more matching elements in the right side source sequence. A group join has no equivalent in
relational terms; it is essentially a sequence of object arrays.
If no elements from the right source sequence are found to match an element in the left source, the join
clause will produce an empty array for that item. Therefore, the group join is still basically an inner-equijoin
except that the result sequence is organized into groups.
If you just select the results of a group join, you can access the items, but you cannot identify the key that they
match on. Therefore, it is generally more useful to select the results of the group join into a new type that also
has the key name, as shown in the previous example.
You can also, of course, use the result of a group join as the generator of another subquery:
var innerGroupJoinQuery2 =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
from prod2 in prodGroup
where prod2.UnitPrice > 2.50M
select prod2;
var leftOuterJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
from item in prodGroup.DefaultIfEmpty(new Product { Name = String.Empty, CategoryID = 0 })
select new { CatName = category.Name, ProdName = item.Name };
Non-equijoins
You can perform non-equijoins, cross joins, and other custom join operations by using multiple from clauses
to introduce new sequences independently into a query. For more information, see Perform custom join
operations.
Composite keys
You can test for equality of multiple values by using a composite key. For more information, see Join by using
composite keys. Composite keys can be also used in a group clause.
Example
The following example compares the results of an inner join, a group join, and a left outer join on the same
data sources by using the same matching keys. Some extra code is added to these examples to clarify the
results in the console display.
class JoinDemonstration
{
#region Data
class Product
{
public string Name { get; set; }
public int CategoryID { get; set; }
}
class Category
{
public string Name { get; set; }
public int ID { get; set; }
}
app.InnerJoin();
app.GroupJoin();
app.GroupInnerJoin();
app.GroupJoin3();
app.LeftOuterJoin();
app.LeftOuterJoin();
app.LeftOuterJoin2();
void InnerJoin()
{
// Create the query that selects
// a property from each element.
var innerJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID
select new { Category = category.ID, Product = prod.Name };
Console.WriteLine("InnerJoin:");
// Execute the query. Access results
// with a simple foreach statement.
foreach (var item in innerJoinQuery)
{
Console.WriteLine("{0,-10}{1}", item.Product, item.Category);
}
Console.WriteLine("InnerJoin: {0} items in 1 group.", innerJoinQuery.Count());
Console.WriteLine(System.Environment.NewLine);
}
void GroupJoin()
{
// This is a demonstration query to show the output
// of a "raw" group join. A more typical group join
// is shown in the GroupInnerJoin method.
var groupJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
select prodGroup;
Console.WriteLine("Simple GroupJoin:");
void GroupInnerJoin()
{
var groupJoinQuery2 =
from category in categories
orderby category.ID
join prod in products on category.ID equals prod.CategoryID into prodGroup
select new
{
Category = category.Name,
Products = from prod2 in prodGroup
orderby prod2.Name
select prod2
select prod2
};
//Console.WriteLine("GroupInnerJoin:");
int totalItems = 0;
Console.WriteLine("GroupInnerJoin:");
foreach (var productGroup in groupJoinQuery2)
{
Console.WriteLine(productGroup.Category);
foreach (var prodItem in productGroup.Products)
{
totalItems++;
Console.WriteLine(" {0,-10} {1}", prodItem.Name, prodItem.CategoryID);
}
}
Console.WriteLine("GroupInnerJoin: {0} items in {1} named groups", totalItems,
groupJoinQuery2.Count());
Console.WriteLine(System.Environment.NewLine);
}
void GroupJoin3()
{
var groupJoinQuery3 =
from category in categories
join product in products on category.ID equals product.CategoryID into prodGroup
from prod in prodGroup
orderby prod.CategoryID
select new { Category = prod.CategoryID, ProductName = prod.Name };
//Console.WriteLine("GroupInnerJoin:");
int totalItems = 0;
Console.WriteLine("GroupJoin3:");
foreach (var item in groupJoinQuery3)
{
totalItems++;
Console.WriteLine(" {0}:{1}", item.ProductName, item.Category);
}
void LeftOuterJoin()
{
// Create the query.
var leftOuterQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
select prodGroup.DefaultIfEmpty(new Product() { Name = "Nothing!", CategoryID = category.ID
});
void LeftOuterJoin2()
{
// Create the query.
var leftOuterQuery2 =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
from item in prodGroup.DefaultIfEmpty()
select new { Name = item == null ? "Nothing!" : item.Name, CategoryID = category.ID };
InnerJoin:
Cola 1
Tea 1
Mustard 2
Pickles 2
Carrots 3
Bok Choy 3
Peaches 5
Melons 5
InnerJoin: 8 items in 1 group.
Unshaped GroupJoin:
Group:
Cola 1
Tea 1
Group:
Mustard 2
Pickles 2
Group:
Carrots 3
Bok Choy 3
Group:
Group:
Peaches 5
Melons 5
Unshaped GroupJoin: 8 items in 5 unnamed groups
GroupInnerJoin:
Beverages
Cola 1
Tea 1
Condiments
Mustard 2
Pickles 2
Vegetables
Bok Choy 3
Carrots 3
Grains
Fruit
Melons 5
Peaches 5
GroupInnerJoin: 8 items in 5 named groups
GroupJoin3:
Cola:1
Tea:1
Mustard:2
Pickles:2
Carrots:3
Bok Choy:3
Peaches:5
Melons:5
GroupJoin3: 8 items in 1 group
Remarks
A join clause that is not followed by into is translated into a Join method call. A join clause that is
followed by into is translated to a GroupJoin method call.
See also
Query Keywords (LINQ)
Language Integrated Query (LINQ)
Join Operations
group clause
Perform left outer joins
Perform inner joins
Perform grouped joins
Order the results of a join clause
Join by using composite keys
Compatible database systems for Visual Studio
let clause (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
In a query expression, it is sometimes useful to store the result of a sub-expression in order to use it in
subsequent clauses. You can do this with the let keyword, which creates a new range variable and initializes it
with the result of the expression you supply. Once initialized with a value, the range variable cannot be used to
store another value. However, if the range variable holds a queryable type, it can be queried.
Example
In the following example let is used in two ways:
1. To create an enumerable type that can itself be queried.
2. To enable the query to call ToLower only one time on the range variable word . Without using let , you
would have to call ToLower in each predicate in the where clause.
class LetSample1
{
static void Main()
{
string[] strings =
{
"A penny saved is a penny earned.",
"The early bird catches the worm.",
"The pen is mightier than the sword."
};
See also
C# Reference
Query Keywords (LINQ)
LINQ in C#
Language Integrated Query (LINQ)
Handle exceptions in query expressions
ascending (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The ascending contextual keyword is used in the orderby clause in query expressions to specify that the sort order
is from smallest to largest. Because ascending is the default sort order, you do not have to specify it.
Example
The following example shows the use of ascending in an orderby clause.
IEnumerable<string> sortAscendingQuery =
from vegetable in vegetables
orderby vegetable ascending
select vegetable;
See also
C# Reference
LINQ in C#
descending
descending (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The descending contextual keyword is used in the orderby clause in query expressions to specify that the sort
order is from largest to smallest.
Example
The following example shows the use of descending in an orderby clause.
IEnumerable<string> sortDescendingQuery =
from vegetable in vegetables
orderby vegetable descending
select vegetable;
See also
C# Reference
LINQ in C#
ascending
on (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The on contextual keyword is used in the join clause of a query expression to specify the join condition.
Example
The following example shows the use of on in a join clause.
var innerJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID
select new { ProductName = prod.Name, Category = category.Name };
See also
C# Reference
Language Integrated Query (LINQ)
equals (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The equals contextual keyword is used in a join clause in a query expression to compare the elements of two
sequences. For more information, see join clause.
Example
The following example shows the use of the equals keyword in a join clause.
var innerJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID
select new { ProductName = prod.Name, Category = category.Name };
See also
Language Integrated Query (LINQ)
by (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The by contextual keyword is used in the group clause in a query expression to specify how the returned items
should be grouped. For more information, see group clause.
Example
The following example shows the use of the by contextual keyword in a group clause to specify that the students
should be grouped according to the first letter of the last name of each student.
See also
LINQ in C#
in (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
See also
C# Keywords
C# Reference
C# operators and expressions (C# reference)
9/3/2020 • 5 minutes to read • Edit Online
C# provides a number of operators. Many of them are supported by the built-in types and allow you to
perform basic operations with values of those types. Those operators include the following groups:
Arithmetic operators that perform arithmetic operations with numeric operands
Comparison operators that compare numeric operands
Boolean logical operators that perform logical operations with bool operands
Bitwise and shift operators that perform bitwise or shift operations with operands of the integral types
Equality operators that check if their operands are equal or not
Typically, you can overload those operators, that is, specify the operator behavior for the operands of a user-
defined type.
The simplest C# expressions are literals (for example, integer and real numbers) and names of variables. You
can combine them into complex expressions by using operators. Operator precedence and associativity
determine the order in which the operations in an expression are performed. You can use parentheses to
change the order of evaluation imposed by operator precedence and associativity.
In the following code, examples of expressions are at the right-hand side of assignments:
int a, b, c;
a = 7;
b = a;
c = b++;
b = a + b * c;
c = a >= 100 ? b : c / 10;
a = (int)Math.Sqrt(b * b + c * c);
Typically, an expression produces a result and can be included in another expression. A void method call is
an example of an expression that doesn't produce a result. It can be used only as a statement, as the
following example shows:
Console.WriteLine("Hello, world!");
var r = 2.3;
var message = $"The area of a circle with radius {r} is {Math.PI * r * r:F3}.";
Console.WriteLine(message);
// Output:
// The area of a circle with radius 2.3 is 16.619.
Query expressions that allow you to use query capabilities directly in C#:
You can use an expression body definition to provide a concise definition for a method, constructor,
property, indexer, or finalizer.
Operator precedence
In an expression with multiple operators, the operators with higher precedence are evaluated before the
operators with lower precedence. In the following example, the multiplication is performed first because it
has higher precedence than addition:
var a = 2 + 2 * 2;
Console.WriteLine(a); // output: 6
var a = (2 + 2) * 2;
Console.WriteLine(a); // output: 8
The following table lists the C# operators starting with the highest precedence to the lowest. The operators
within each row have the same precedence.
O P ERATO RS C AT EGO RY O R N A M E
x.y, f(x), a[i], x?.y , x?[y] , x++, x--, x!, new, typeof, Primary
checked, unchecked, default, nameof, delegate, sizeof,
stackalloc, x->y
+x, -x, !x, ~x, ++x, --x, ^x, (T)x, await, &x, *x, true and false Unary
x..y Range
x * y, x / y, x % y Multiplicative
x + y, x – y Additive
O P ERATO RS C AT EGO RY O R N A M E
x == y, x != y Equality
x || y Conditional OR
x ?? y Null-coalescing operator
Operator associativity
When operators have the same precedence, associativity of the operators determines the order in which the
operations are performed:
Left-associative operators are evaluated in order from left to right. Except for the assignment operators
and the null-coalescing operators, all binary operators are left-associative. For example, a + b - c is
evaluated as (a + b) - c .
Right-associative operators are evaluated in order from right to left. The assignment operators, the null-
coalescing operators, and the conditional operator ?: are right-associative. For example, x = y = z is
evaluated as x = (y = z) .
int a = 13 / 5 / 2;
int b = 13 / (5 / 2);
Console.WriteLine($"a = {a}, b = {b}"); // output: a = 1, b = 6
Operand evaluation
Unrelated to operator precedence and associativity, operands in an expression are evaluated from left to
right. The following examples demonstrate the order in which operators and operands are evaluated:
a + b a, b, +
EXP RESSIO N O RDER O F EVA L UAT IO N
a + b * c a, b, c, *, +
a / b + c * d a, b, /, c, d, *, +
a / (b + c) * d a, b, c, +, /, d, *
Typically, all operator operands are evaluated. However, some operators evaluate operands conditionally.
That is, the value of the leftmost operand of such an operator defines if (or which) other operands should be
evaluated. These operators are the conditional logical AND ( && ) and OR ( || ) operators, the null-
coalescing operators ?? and ??= , the null-conditional operators ?. and ?[] , and the conditional
operator ?: . For more information, see the description of each operator.
C# language specification
For more information, see the following sections of the C# language specification:
Expressions
Operators
See also
C# reference
Operator overloading
Expression trees
Arithmetic operators (C# reference)
9/3/2020 • 9 minutes to read • Edit Online
The following operators perform arithmetic operations with operands of numeric types:
Unary ++ (increment), -- (decrement), + (plus), and - (minus) operators
Binary * (multiplication), / (division), % (remainder), + (addition), and - (subtraction) operators
Those operators are supported by all integral and floating-point numeric types.
In the case of integral types, those operators (except the ++ and -- operators) are defined for the int , uint ,
long , and ulong types. When operands are of other integral types ( sbyte , byte , short , ushort , or char ),
their values are converted to the int type, which is also the result type of an operation. When operands are of
different integral or floating-point types, their values are converted to the closest containing type, if such a type
exists. For more information, see the Numeric promotions section of the C# language specification. The ++ and
-- operators are defined for all integral and floating-point numeric types and the char type.
Increment operator ++
The unary increment operator ++ increments its operand by 1. The operand must be a variable, a property
access, or an indexer access.
The increment operator is supported in two forms: the postfix increment operator, x++ , and the prefix increment
operator, ++x .
Postfix increment operator
The result of x++ is the value of x before the operation, as the following example shows:
int i = 3;
Console.WriteLine(i); // output: 3
Console.WriteLine(i++); // output: 3
Console.WriteLine(i); // output: 4
double a = 1.5;
Console.WriteLine(a); // output: 1.5
Console.WriteLine(++a); // output: 2.5
Console.WriteLine(a); // output: 2.5
Decrement operator --
The unary decrement operator -- decrements its operand by 1. The operand must be a variable, a property
access, or an indexer access.
The decrement operator is supported in two forms: the postfix decrement operator, x-- , and the prefix
decrement operator, --x .
Postfix decrement operator
The result of x-- is the value of x before the operation, as the following example shows:
int i = 3;
Console.WriteLine(i); // output: 3
Console.WriteLine(i--); // output: 3
Console.WriteLine(i); // output: 2
double a = 1.5;
Console.WriteLine(a); // output: 1.5
Console.WriteLine(--a); // output: 0.5
Console.WriteLine(a); // output: 0.5
Console.WriteLine(+4); // output: 4
Console.WriteLine(-4); // output: -4
Console.WriteLine(-(-4)); // output: 4
uint a = 5;
var b = -a;
Console.WriteLine(b); // output: -5
Console.WriteLine(b.GetType()); // output: System.Int64
Multiplication operator *
The multiplication operator * computes the product of its operands:
Division operator /
The division operator / divides its left-hand operand by its right-hand operand.
Integer division
For the operands of integer types, the result of the / operator is of an integer type and equals the quotient of
the two operands rounded towards zero:
Console.WriteLine(13 / 5); // output: 2
Console.WriteLine(-13 / 5); // output: -2
Console.WriteLine(13 / -5); // output: -2
Console.WriteLine(-13 / -5); // output: 2
To obtain the quotient of the two operands as a floating-point number, use the float , double , or decimal type:
int a = 13;
int b = 5;
Console.WriteLine((double)a / b); // output: 2.6
Floating-point division
For the float , double , and decimal types, the result of the / operator is the quotient of the two operands:
If one of the operands is decimal , another operand can be neither float nor double , because neither float
nor double is implicitly convertible to decimal . You must explicitly convert the float or double operand to the
decimal type. For more information about conversions between numeric types, see Built-in numeric conversions.
Remainder operator %
The remainder operator % computes the remainder after dividing its left-hand operand by its right-hand
operand.
Integer remainder
For the operands of integer types, the result of a % b is the value produced by a - (a / b) * b . The sign of the
non-zero remainder is the same as that of the left-hand operand, as the following example shows:
Use the Math.DivRem method to compute both integer division and remainder results.
Floating-point remainder
For the float and double operands, the result of x % y for the finite x and y is the value z such that
The sign of z , if non-zero, is the same as the sign of x .
The absolute value of z is the value produced by |x| - n * |y| where n is the largest possible integer that
is less than or equal to |x| / |y| and |x| and |y| are the absolute values of x and y , respectively.
NOTE
This method of computing the remainder is analogous to that used for integer operands, but different from the IEEE 754
specification. If you need the remainder operation that complies with the IEEE 754 specification, use the
Math.IEEERemainder method.
For information about the behavior of the % operator with non-finite operands, see the Remainder operator
section of the C# language specification.
For the decimal operands, the remainder operator % is equivalent to the remainder operator of the
System.Decimal type.
The following example demonstrates the behavior of the remainder operator with floating-point operands:
Addition operator +
The addition operator + computes the sum of its operands:
You can also use the + operator for string concatenation and delegate combination. For more information, see
the + and += operators article.
Subtraction operator -
The subtraction operator - subtracts its right-hand operand from its left-hand operand:
You can also use the - operator for delegate removal. For more information, see the - and -= operators
article.
Compound assignment
For a binary operator op , a compound assignment expression of the form
x op= y
is equivalent to
x = x op y
a -= 4;
Console.WriteLine(a); // output: 10
a *= 2;
Console.WriteLine(a); // output: 20
a /= 4;
Console.WriteLine(a); // output: 5
a %= 3;
Console.WriteLine(a); // output: 2
Because of numeric promotions, the result of the op operation might be not implicitly convertible to the type T
of x . In such a case, if op is a predefined operator and the result of the operation is explicitly convertible to the
type T of x , a compound assignment expression of the form x op= y is equivalent to x = (T)(x op y) , except
that x is only evaluated once. The following example demonstrates that behavior:
byte a = 200;
byte b = 100;
var c = a + b;
Console.WriteLine(c.GetType()); // output: System.Int32
Console.WriteLine(c); // output: 300
a += b;
Console.WriteLine(a); // output: 44
You also use the += and -= operators to subscribe to and unsubscribe from an event, respectively. For more
information, see How to subscribe to and unsubscribe from events.
For the complete list of C# operators ordered by precedence level, see the Operator precedence section of the C#
operators article.
Arithmetic overflow and division by zero
When the result of an arithmetic operation is outside the range of possible finite values of the involved numeric
type, the behavior of an arithmetic operator depends on the type of its operands.
Integer arithmetic overflow
Integer division by zero always throws a DivideByZeroException.
In case of integer arithmetic overflow, an overflow checking context, which can be checked or unchecked, controls
the resulting behavior:
In a checked context, if overflow happens in a constant expression, a compile-time error occurs. Otherwise,
when the operation is performed at run time, an OverflowException is thrown.
In an unchecked context, the result is truncated by discarding any high-order bits that don't fit in the
destination type.
Along with the checked and unchecked statements, you can use the checked and unchecked operators to control
the overflow checking context, in which an expression is evaluated:
int a = int.MaxValue;
int b = 3;
For the operands of the decimal type, arithmetic overflow always throws an OverflowException and division by
zero always throws a DivideByZeroException.
Round-off errors
Because of general limitations of the floating-point representation of real numbers and floating-point arithmetic,
round-off errors might occur in calculations with floating-point types. That is, the produced result of an
expression might differ from the expected mathematical result. The following example demonstrates several such
cases:
Console.WriteLine(.41f % .2f); // output: 0.00999999
double a = 0.1;
double b = 3 * a;
Console.WriteLine(b == 0.3); // output: False
Console.WriteLine(b - 0.3); // output: 5.55111512312578E-17
decimal c = 1 / 3.0m;
decimal d = 3 * c;
Console.WriteLine(d == 1.0m); // output: False
Console.WriteLine(d); // output: 0.9999999999999999999999999999
For more information, see remarks at the System.Double, System.Single, or System.Decimal reference pages.
Operator overloadability
A user-defined type can overload the unary ( ++ , -- , + , and - ) and binary ( * , / , % , + , and - ) arithmetic
operators. When a binary operator is overloaded, the corresponding compound assignment operator is also
implicitly overloaded. A user-defined type cannot explicitly overload a compound assignment operator.
C# language specification
For more information, see the following sections of the C# language specification:
Postfix increment and decrement operators
Prefix increment and decrement operators
Unary plus operator
Unary minus operator
Multiplication operator
Division operator
Remainder operator
Addition operator
Subtraction operator
Compound assignment
The checked and unchecked operators
Numeric promotions
See also
C# reference
C# operators and expressions
System.Math
System.MathF
Numerics in .NET
Boolean logical operators (C# reference)
9/3/2020 • 7 minutes to read • Edit Online
Beginning with C# 8.0, the unary postfix ! operator is the null-forgiving operator.
bool SecondOperand()
{
Console.WriteLine("Second operand is evaluated.");
return true;
}
For operands of the integral numeric types, the ^ operator computes the bitwise logical exclusive OR of its
operands.
Logical OR operator |
The | operator computes the logical OR of its operands. The result of x | y is true if either x or y
evaluates to true . Otherwise, the result is false .
The | operator evaluates both operands even if the left-hand operand evaluates to true , so that the operation
result is true regardless of the value of the right-hand operand.
In the following example, the right-hand operand of the | operator is a method call, which is performed
regardless of the value of the left-hand operand:
bool SecondOperand()
{
Console.WriteLine("Second operand is evaluated.");
return true;
}
The conditional logical OR operator || also computes the logical OR of its operands, but doesn't evaluate the
right-hand operand if the left-hand operand evaluates to true .
For operands of the integral numeric types, the | operator computes the bitwise logical OR of its operands.
bool SecondOperand()
{
Console.WriteLine("Second operand is evaluated.");
return true;
}
The logical AND operator & also computes the logical AND of its operands, but always evaluates both operands.
bool SecondOperand()
{
Console.WriteLine("Second operand is evaluated.");
return true;
}
The logical OR operator | also computes the logical OR of its operands, but always evaluates both operands.
The | operator produces false only if both its operands evaluate to false . If either x or y evaluates
to true , x | y produces true (even if another operand evaluates to null ). Otherwise, the result of
x | y is null .
X Y X& Y X|Y
The behavior of those operators differs from the typical operator behavior with nullable value types. Typically, an
operator which is defined for operands of a value type can be also used with operands of the corresponding
nullable value type. Such an operator produces null if any of its operands evaluates to null . However, the &
and | operators can produce non-null even if one of the operands evaluates to null . For more information
about the operator behavior with nullable value types, see the Lifted operators section of the Nullable value
types article.
You can also use the ! and ^ operators with bool? operands, as the following example shows:
The conditional logical operators && and || don't support bool? operands.
Compound assignment
For a binary operator op , a compound assignment expression of the form
x op= y
is equivalent to
x = x op y
test |= true;
Console.WriteLine(test); // output: True
test ^= false;
Console.WriteLine(test); // output: True
NOTE
The conditional logical operators && and || don't support compound assignment.
Operator precedence
The following list orders logical operators starting from the highest precedence to the lowest:
Logical negation operator !
Logical AND operator &
Logical exclusive OR operator ^
Logical OR operator |
Conditional logical AND operator &&
Conditional logical OR operator ||
Operator overloadability
A user-defined type can overload the ! , & , | , and ^ operators. When a binary operator is overloaded, the
corresponding compound assignment operator is also implicitly overloaded. A user-defined type cannot
explicitly overload a compound assignment operator.
A user-defined type cannot overload the conditional logical operators && and || . However, if a user-defined
type overloads the true and false operators and the & or | operator in a certain way, the && or || operation,
respectively, can be evaluated for the operands of that type. For more information, see the User-defined
conditional logical operators section of the C# language specification.
C# language specification
For more information, see the following sections of the C# language specification:
Logical negation operator
Logical operators
Conditional logical operators
Compound assignment
See also
C# reference
C# operators and expressions
Bitwise and shift operators
Bitwise and shift operators (C# reference)
9/3/2020 • 7 minutes to read • Edit Online
The following operators perform bitwise or shift operations with operands of the integral numeric types or the
char type:
Unary ~ (bitwise complement) operator
Binary << (left shift) and >> (right shift) shift operators
Binary & (logical AND), | (logical OR), and ^ (logical exclusive OR) operators
Those operators are defined for the int , uint , long , and ulong types. When both operands are of other
integral types ( sbyte , byte , short , ushort , or char ), their values are converted to the int type, which is also
the result type of an operation. When operands are of different integral types, their values are converted to the
closest containing integral type. For more information, see the Numeric promotions section of the C# language
specification.
The & , | , and ^ operators are also defined for operands of the bool type. For more information, see Boolean
logical operators.
Bitwise and shift operations never cause overflow and produce the same results in checked and unchecked
contexts.
uint a = 0b_0000_1111_0000_1111_0000_1111_0000_1100;
uint b = ~a;
Console.WriteLine(Convert.ToString(b, toBase: 2));
// Output:
// 11110000111100001111000011110011
You can also use the ~ symbol to declare finalizers. For more information, see Finalizers.
uint x = 0b_1100_1001_0000_0000_0000_0000_0001_0001;
Console.WriteLine($"Before: {Convert.ToString(x, toBase: 2)}");
uint y = x << 4;
Console.WriteLine($"After: {Convert.ToString(y, toBase: 2)}");
// Output:
// Before: 11001001000000000000000000010001
// After: 10010000000000000000000100010000
Because the shift operators are defined only for the int , uint , long , and ulong types, the result of an
operation always contains at least 32 bits. If the left-hand operand is of another integral type ( sbyte , byte ,
short , ushort , or char ), its value is converted to the int type, as the following example shows:
byte a = 0b_1111_0001;
var b = a << 8;
Console.WriteLine(b.GetType());
Console.WriteLine($"Shifted byte: {Convert.ToString(b, toBase: 2)}");
// Output:
// System.Int32
// Shifted byte: 1111000100000000
For information about how the right-hand operand of the << operator defines the shift count, see the Shift count
of the shift operators section.
uint x = 0b_1001;
Console.WriteLine($"Before: {Convert.ToString(x, toBase: 2), 4}");
uint y = x >> 2;
Console.WriteLine($"After: {Convert.ToString(y, toBase: 2), 4}");
// Output:
// Before: 1001
// After: 10
The high-order empty bit positions are set based on the type of the left-hand operand as follows:
If the left-hand operand is of type int or long , the right-shift operator performs an arithmetic shift: the
value of the most significant bit (the sign bit) of the left-hand operand is propagated to the high-order
empty bit positions. That is, the high-order empty bit positions are set to zero if the left-hand operand is
non-negative and set to one if it's negative.
int a = int.MinValue;
Console.WriteLine($"Before: {Convert.ToString(a, toBase: 2)}");
int b = a >> 3;
Console.WriteLine($"After: {Convert.ToString(b, toBase: 2)}");
// Output:
// Before: 10000000000000000000000000000000
// After: 11110000000000000000000000000000
If the left-hand operand is of type uint or ulong , the right-shift operator performs a logical shift: the
high-order empty bit positions are always set to zero.
uint c = 0b_1000_0000_0000_0000_0000_0000_0000_0000;
Console.WriteLine($"Before: {Convert.ToString(c, toBase: 2), 32}");
uint d = c >> 3;
Console.WriteLine($"After: {Convert.ToString(d, toBase: 2), 32}");
// Output:
// Before: 10000000000000000000000000000000
// After: 10000000000000000000000000000
For information about how the right-hand operand of the >> operator defines the shift count, see the Shift count
of the shift operators section.
uint a = 0b_1111_1000;
uint b = 0b_1001_1101;
uint c = a & b;
Console.WriteLine(Convert.ToString(c, toBase: 2));
// Output:
// 10011000
For bool operands, the & operator computes the logical AND of its operands. The unary & operator is the
address-of operator.
uint a = 0b_1111_1000;
uint b = 0b_0001_1100;
uint c = a ^ b;
Console.WriteLine(Convert.ToString(c, toBase: 2));
// Output:
// 11100100
For bool operands, the ^ operator computes the logical exclusive OR of its operands.
Logical OR operator |
The | operator computes the bitwise logical OR of its operands:
uint a = 0b_1010_0000;
uint b = 0b_1001_0001;
uint c = a | b;
Console.WriteLine(Convert.ToString(c, toBase: 2));
// Output:
// 10110001
For bool operands, the | operator computes the logical OR of its operands.
Compound assignment
For a binary operator op , a compound assignment expression of the form
x op= y
is equivalent to
x = x op y
uint a = 0b_1111_1000;
a &= 0b_1001_1101;
Display(a); // output: 10011000
a |= 0b_0011_0001;
Display(a); // output: 10111001
a ^= 0b_1000_0000;
Display(a); // output: 111001
a <<= 2;
Display(a); // output: 11100100
a >>= 4;
Display(a); // output: 1110
Because of numeric promotions, the result of the op operation might be not implicitly convertible to the type T
of x . In such a case, if op is a predefined operator and the result of the operation is explicitly convertible to the
type T of x , a compound assignment expression of the form x op= y is equivalent to x = (T)(x op y) , except
that x is only evaluated once. The following example demonstrates that behavior:
byte x = 0b_1111_0001;
int b = x << 8;
Console.WriteLine($"{Convert.ToString(b, toBase: 2)}"); // output: 1111000100000000
x <<= 8;
Console.WriteLine(x); // output: 0
Operator precedence
The following list orders bitwise and shift operators starting from the highest precedence to the lowest:
Bitwise complement operator ~
Shift operators << and >>
Logical AND operator &
Logical exclusive OR operator ^
Logical OR operator |
Use parentheses, () , to change the order of evaluation imposed by operator precedence:
uint a = 0b_1101;
uint b = 0b_1001;
uint c = 0b_1010;
uint d1 = a | b & c;
Display(d1); // output: 1101
uint d2 = (a | b) & c;
Display(d2); // output: 1000
For the complete list of C# operators ordered by precedence level, see the Operator precedence section of the C#
operators article.
int a = 0b_0001;
Console.WriteLine($"{a} << {count1} is {a << count1}; {a} << {count2} is {a << count2}");
// Output:
// 1 << 1 is 2; 1 << 225 is 2
int b = 0b_0100;
Console.WriteLine($"{b} >> {count1} is {b >> count1}; {b} >> {count2} is {b >> count2}");
// Output:
// 4 >> 1 is 2; 4 >> 225 is 2
NOTE
As the preceding example shows, the result of a shift operation can be non-zero even if the value of the right-hand operand
is greater than the number of bits in the left-hand operand.
Operator overloadability
A user-defined type can overload the ~ , << , >> , & , | , and ^ operators. When a binary operator is
overloaded, the corresponding compound assignment operator is also implicitly overloaded. A user-defined type
cannot explicitly overload a compound assignment operator.
If a user-defined type T overloads the << or >> operator, the type of the left-hand operand must be T and the
type of the right-hand operand must be int .
C# language specification
For more information, see the following sections of the C# language specification:
Bitwise complement operator
Shift operators
Logical operators
Compound assignment
Numeric promotions
See also
C# reference
C# operators and expressions
Boolean logical operators
Equality operators (C# reference)
9/3/2020 • 3 minutes to read • Edit Online
The == (equality) and != (inequality) operators check if their operands are equal or not.
Equality operator ==
The equality operator == returns true if its operands are equal, false otherwise.
Value types equality
Operands of the built-in value types are equal if their values are equal:
int a = 1 + 2 + 3;
int b = 6;
Console.WriteLine(a == b); // output: True
char c1 = 'a';
char c2 = 'A';
Console.WriteLine(c1 == c2); // output: False
Console.WriteLine(c1 == char.ToLower(c2)); // output: True
NOTE
For the == , < , > , <= , and >= operators, if any of the operands is not a number (Double.NaN or Single.NaN), the
result of operation is false . That means that the NaN value is neither greater than, less than, nor equal to any other
double (or float ) value, including NaN . For more information and examples, see the Double.NaN or Single.NaN
reference article.
Two operands of the same enum type are equal if the corresponding values of the underlying integral type are
equal.
User-defined struct types don't support the == operator by default. To support the == operator, a user-defined
struct must overload it.
Beginning with C# 7.3, the == and != operators are supported by C# tuples. For more information, see the
Tuple equality section of the Tuple types article.
Reference types equality
By default, two reference-type operands are equal if they refer to the same object:
public class ReferenceTypesEquality
{
public class MyClass
{
private int id;
As the example shows, user-defined reference types support the == operator by default. However, a reference
type can overload the == operator. If a reference type overloads the == operator, use the
Object.ReferenceEquals method to check if two references of that type refer to the same object.
String equality
Two string operands are equal when both of them are null or both string instances are of the same length and
have identical characters in each character position:
string s1 = "hello!";
string s2 = "HeLLo!";
Console.WriteLine(s1 == s2.ToLower()); // output: True
string s3 = "Hello!";
Console.WriteLine(s1 == s3); // output: False
That is a case-sensitive ordinal comparison. For more information about string comparison, see How to compare
strings in C#.
Delegate equality
Two delegate operands of the same runtime type are equal when both of them are null or their invocation lists
are of the same length and have equal entries in each position:
Action b = a + a;
Action c = a + a;
Console.WriteLine(object.ReferenceEquals(b, c)); // output: False
Console.WriteLine(b == c); // output: True
For more information, see the Delegate equality operators section of the C# language specification.
Delegates that are produced from evaluation of semantically identical lambda expressions are not equal, as the
following example shows:
Action a = () => Console.WriteLine("a");
Action b = () => Console.WriteLine("a");
Inequality operator !=
The inequality operator != returns true if its operands are not equal, false otherwise. For the operands of
the built-in types, the expression x != y produces the same result as the expression !(x == y) . For more
information about type equality, see the Equality operator section.
The following example demonstrates the usage of the != operator:
int a = 1 + 1 + 2 + 3;
int b = 6;
Console.WriteLine(a != b); // output: True
string s1 = "Hello";
string s2 = "Hello";
Console.WriteLine(s1 != s2); // output: False
object o1 = 1;
object o2 = 1;
Console.WriteLine(o1 != o2); // output: True
Operator overloadability
A user-defined type can overload the == and != operators. If a type overloads one of the two operators, it must
also overload the other one.
C# language specification
For more information, see the Relational and type-testing operators section of the C# language specification.
See also
C# reference
C# operators and expressions
System.IEquatable<T>
Object.Equals
Object.ReferenceEquals
Equality comparisons
Comparison operators
Comparison operators (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
The < (less than), > (greater than), <= (less than or equal), and >= (greater than or equal) comparison, also
known as relational, operators compare their operands. Those operators are supported by all integral and
floating-point numeric types.
NOTE
For the == , < , > , <= , and >= operators, if any of the operands is not a number (Double.NaN or Single.NaN), the
result of operation is false . That means that the NaN value is neither greater than, less than, nor equal to any other
double (or float ) value, including NaN . For more information and examples, see the Double.NaN or Single.NaN
reference article.
The char type also supports comparison operators. In the case of char operands, the corresponding character
codes are compared.
Enumeration types also support comparison operators. For operands of the same enum type, the corresponding
values of the underlying integral type are compared.
The == and != operators check if their operands are equal or not.
Operator overloadability
A user-defined type can overload the < , > , <= , and >= operators.
If a type overloads one of the < or > operators, it must overload both < and > . If a type overloads one of the
<= or >= operators, it must overload both <= and >= .
C# language specification
For more information, see the Relational and type-testing operators section of the C# language specification.
See also
C# reference
C# operators and expressions
System.IComparable<T>
Equality operators
Member access operators and expressions (C#
reference)
9/3/2020 • 8 minutes to read • Edit Online
You can use the following operators and expressions when you access a type member:
. (member access): to access a member of a namespace or a type
[] (array element or indexer access): to access an array element or a type indexer
?. and ?[] (null-conditional operators): to perform a member or element access operation only if an operand
is non-null
() (invocation): to call an accessed method or invoke a delegate
^ (index from end): to indicate that the element position is from the end of a sequence
.. (range): to specify a range of indices that you can use to obtain a range of sequence elements
using System.Collections.Generic;
Use . to form a qualified name to access a type within a namespace, as the following code shows:
Indexer operator []
Square brackets, [] , are typically used for array, indexer, or pointer element access.
Array access
The following example demonstrates how to access array elements:
int[] fib = new int[10];
fib[0] = fib[1] = 1;
for (int i = 2; i < fib.Length; i++)
{
fib[i] = fib[i - 1] + fib[i - 2];
}
Console.WriteLine(fib[fib.Length - 1]); // output: 55
If an array index is outside the bounds of the corresponding dimension of an array, an IndexOutOfRangeException
is thrown.
As the preceding example shows, you also use square brackets when you declare an array type or instantiate an
array instance.
For more information about arrays, see Arrays.
Indexer access
The following example uses the .NET Dictionary<TKey,TValue> type to demonstrate indexer access:
Indexers allow you to index instances of a user-defined type in the similar way as array indexing. Unlike array
indices, which must be integer, the indexer parameters can be declared to be of any type.
For more information about indexers, see Indexers.
Other usages of []
For information about pointer element access, see the Pointer element access operator [] section of the Pointer
related operators article.
You also use square brackets to specify attributes:
[System.Diagnostics.Conditional("DEBUG")]
void TraceMethod() {}
The null-conditional operators are short-circuiting. That is, if one operation in a chain of conditional member or
element access operations returns null , the rest of the chain doesn't execute. In the following example, B is not
evaluated if A evaluates to null and C is not evaluated if A or B evaluates to null :
A?.B?.Do(C);
A?.B?[C];
The following example demonstrates the usage of the ?. and ?[] operators:
The preceding example also uses the null-coalescing operator ?? to specify an alternative expression to evaluate
in case the result of a null-conditional operation is null .
If a.x or a[x] is of a non-nullable value type T , a?.x or a?[x] is of the corresponding nullable value type T? .
If you need an expression of type T , apply the null-coalescing operator ?? to a null-conditional expression, as the
following example shows:
Console.WriteLine(GetSumOfFirstTwoOrDefault(null)); // output: 0
Console.WriteLine(GetSumOfFirstTwoOrDefault(new int[0])); // output: 0
Console.WriteLine(GetSumOfFirstTwoOrDefault(new[] { 3, 4, 5 })); // output: 7
In the preceding example, if you don't use the ?? operator, numbers?.Length < 2 evaluates to false when
numbers is null .
The null-conditional member access operator ?. is also known as the Elvis operator.
NOTE
In C# 8, the null-forgiving operator terminates the list of preceding null-conditional operations. For example, the expression
x?.y!.z is parsed as (x?.y)!.z . Due to this interpretation, z is evaluated even if x is null , which may result in a
NullReferenceException.
PropertyChanged?.Invoke(…)
That code is equivalent to the following code that you would use in C# 5 or earlier:
That is a thread-safe way to ensure that only a non-null handler is invoked. Because delegate instances are
immutable, no thread can change the object referenced by the handler local variable. In particular, if the code
executed by another thread unsubscribes from the PropertyChanged event and PropertyChanged becomes null
before handler is invoked, the object referenced by handler remains unaffected. The ?. operator evaluates its
left-hand operand no more than once, guaranteeing that it cannot be changed to null after being verified as non-
null.
Invocation expression ()
Use parentheses, () , to call a method or invoke a delegate.
The following example demonstrates how to call a method, with or without arguments, and invoke a delegate:
numbers.Clear();
display(numbers.Count); // output: 0
You also use parentheses when you invoke a constructor with the new operator.
Other usages of ()
You also use parentheses to adjust the order in which to evaluate operations in an expression. For more
information, see C# operators.
Cast expressions, which perform explicit type conversions, also use parentheses.
As the preceding example shows, expression ^e is of the System.Index type. In expression ^e , the result of e
must be implicitly convertible to int .
You can also use the ^ operator with the range operator to create a range of indices. For more information, see
Indices and ranges.
Range operator ..
Available in C# 8.0 and later, the .. operator specifies the start and end of a range of indices as its operands. The
left-hand operand is an inclusive start of a range. The right-hand operand is an exclusive end of a range. Either of
operands can be an index from the start or from the end of a sequence, as the following example shows:
int margin = 1;
int[] inner = numbers[margin..^margin];
Display(inner); // output: 10 20 30 40
As the preceding example shows, expression a..b is of the System.Range type. In expression a..b , the results of
a and b must be implicitly convertible to int or Index.
You can omit any of the operands of the .. operator to obtain an open-ended range:
a.. is equivalent to a..^0
..b is equivalent to 0..b
.. is equivalent to 0..^0
int[] numbers = new[] { 0, 10, 20, 30, 40, 50 };
int amountToDrop = numbers.Length / 2;
Operator overloadability
The . , () , ^ , and .. operators cannot be overloaded. The [] operator is also considered a non-overloadable
operator. Use indexers to support indexing with user-defined types.
C# language specification
For more information, see the following sections of the C# language specification:
Member access
Element access
Null-conditional operator
Invocation expressions
For more information about indices and ranges, see the feature proposal note.
See also
C# reference
C# operators and expressions
?? (null-coalescing operator)
:: operator
Type-testing operators and cast expression (C#
reference)
9/3/2020 • 6 minutes to read • Edit Online
You can use the following operators and expressions to perform type checking or type conversion:
is operator: to check if the runtime type of an expression is compatible with a given type
as operator: to explicitly convert an expression to a given type if its runtime type is compatible with that type
cast expression: to perform an explicit conversion
typeof operator: to obtain the System.Type instance for a type
is operator
The is operator checks if the runtime type of an expression result is compatible with a given type. Beginning with
C# 7.0, the is operator also tests an expression result against a pattern.
The expression with the type-testing is operator has the following form
E is T
where E is an expression that returns a value and T is the name of a type or a type parameter. E cannot be an
anonymous method or a lambda expression.
The E is T expression returns true if the result of E is non-null and can be converted to type T by a reference
conversion, a boxing conversion, or an unboxing conversion; otherwise, it returns false . The is operator doesn't
consider user-defined conversions.
The following example demonstrates that the is operator returns true if the runtime type of an expression
result derives from a given type, that is, there exists a reference conversion between types:
The next example shows that the is operator takes into account boxing and unboxing conversions but doesn't
consider numeric conversions:
int i = 27;
Console.WriteLine(i is System.IFormattable); // output: True
object iBoxed = i;
Console.WriteLine(iBoxed is int); // output: True
Console.WriteLine(iBoxed is long); // output: False
For information about C# conversions, see the Conversions chapter of the C# language specification.
Type testing with pattern matching
Beginning with C# 7.0, the is operator also tests an expression result against a pattern. In particular, it supports
the type pattern in the following form:
E is T v
where E is an expression that returns a value, T is the name of a type or a type parameter, and v is a new local
variable of type T . If the result of E is non-null and can be converted to T by a reference, boxing, or unboxing
conversion, the E is T v expression returns true and the converted value of the result of E is assigned to
variable v .
The following example demonstrates the usage of the is operator with the type pattern:
int i = 23;
object iBoxed = i;
int? jNullable = 7;
if (iBoxed is int a && jNullable is int b)
{
Console.WriteLine(a + b); // output 30
}
For more information about the type pattern and other supported patterns, see Pattern matching with is.
as operator
The as operator explicitly converts the result of an expression to a given reference or nullable value type. If the
conversion is not possible, the as operator returns null . Unlike a cast expression, the as operator never throws
an exception.
The expression of the form
E as T
where E is an expression that returns a value and T is the name of a type or a type parameter, produces the
same result as
E is T ? (T)(E) : (T)null
NOTE
As the preceding example shows, you need to compare the result of the as expression with null to check if the
conversion is successful. Beginning with C# 7.0, you can use the is operator both to test if the conversion succeeds and, if it
succeeds, assign its result to a new variable.
Cast expression
A cast expression of the form (T)E performs an explicit conversion of the result of expression E to type T . If no
explicit conversion exists from the type of E to type T , a compile-time error occurs. At run time, an explicit
conversion might not succeed and a cast expression might throw an exception.
The following example demonstrates explicit numeric and reference conversions:
double x = 1234.7;
int a = (int)x;
Console.WriteLine(a); // output: 1234
For information about supported explicit conversions, see the Explicit conversions section of the C# language
specification. For information about how to define a custom explicit or implicit type conversion, see User-defined
conversion operators.
Other usages of ()
You also use parentheses to call a method or invoke a delegate.
Other use of parentheses is to adjust the order in which to evaluate operations in an expression. For more
information, see C# operators.
typeof operator
The typeof operator obtains the System.Type instance for a type. The argument to the typeof operator must be
the name of a type or a type parameter, as the following example shows:
Console.WriteLine(typeof(List<string>));
PrintType<int>();
PrintType<System.Int32>();
PrintType<Dictionary<int, char>>();
// Output:
// System.Collections.Generic.List`1[System.String]
// System.Int32
// System.Int32
// System.Collections.Generic.Dictionary`2[System.Int32,System.Char]
You can also use the typeof operator with unbound generic types. The name of an unbound generic type must
contain the appropriate number of commas, which is one less than the number of type parameters. The following
example shows the usage of the typeof operator with an unbound generic type:
Console.WriteLine(typeof(Dictionary<,>));
// Output:
// System.Collections.Generic.Dictionary`2[TKey,TValue]
An expression cannot be an argument of the typeof operator. To get the System.Type instance for the runtime
type of an expression result, use the Object.GetType method.
Type testing with the typeof operator
Use the typeof operator to check if the runtime type of the expression result exactly matches a given type. The
following example demonstrates the difference between type checking performed with the typeof operator and
the is operator:
Operator overloadability
The is , as , and typeof operators cannot be overloaded.
A user-defined type cannot overload the () operator, but can define custom type conversions that can be
performed by a cast expression. For more information, see User-defined conversion operators.
C# language specification
For more information, see the following sections of the C# language specification:
The is operator
The as operator
Cast expressions
The typeof operator
See also
C# reference
C# operators and expressions
How to safely cast by using pattern matching and the is and as operators
Generics in .NET
User-defined conversion operators (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
A user-defined type can define a custom implicit or explicit conversion from or to another type.
Implicit conversions don't require special syntax to be invoked and can occur in a variety of situations, for
example, in assignments and methods invocations. Predefined C# implicit conversions always succeed and never
throw an exception. User-defined implicit conversions should behave in that way as well. If a custom conversion
can throw an exception or lose information, define it as an explicit conversion.
User-defined conversions are not considered by the is and as operators. Use a cast expression to invoke a user-
defined explicit conversion.
Use the operator and implicit or explicit keywords to define an implicit or explicit conversion, respectively.
The type that defines a conversion must be either a source type or a target type of that conversion. A conversion
between two user-defined types can be defined in either of the two types.
The following example demonstrates how to define an implicit and explicit conversion:
using System;
byte number = d;
Console.WriteLine(number); // output: 7
You also use the operator keyword to overload a predefined C# operator. For more information, see Operator
overloading.
C# language specification
For more information, see the following sections of the C# language specification:
Conversion operators
User-defined conversions
Implicit conversions
Explicit conversions
See also
C# reference
C# operators and expressions
Operator overloading
Type-testing and cast operators
Casting and type conversion
Design guidelines - Conversion operators
Chained user-defined explicit conversions in C#
Pointer related operators (C# reference)
9/3/2020 • 7 minutes to read • Edit Online
NOTE
Any operation with pointers requires an unsafe context. The code that contains unsafe blocks must be compiled with the
-unsafe compiler option.
unsafe
{
int number = 27;
int* pointerToNumber = &number;
The operand of the & operator must be a fixed variable. Fixed variables are variables that reside in storage
locations that are unaffected by operation of the garbage collector. In the preceding example, the local variable
number is a fixed variable, because it resides on the stack. Variables that reside in storage locations that can be
affected by the garbage collector (for example, relocated) are called movable variables. Object fields and array
elements are examples of movable variables. You can get the address of a movable variable if you "fix", or "pin", it
with a fixed statement. The obtained address is valid only inside the block of a fixed statement. The following
example shows how to use a fixed statement and the & operator:
unsafe
{
byte[] bytes = { 1, 2, 3 };
fixed (byte* pointerToFirst = &bytes[0])
{
// The address stored in pointerToFirst
// is valid only inside this fixed statement block.
}
}
You can't get the address of a constant or a value.
For more information about fixed and movable variables, see the Fixed and moveable variables section of the C#
language specification.
The binary & operator computes the logical AND of its Boolean operands or the bitwise logical AND of its integral
operands.
unsafe
{
char letter = 'A';
char* pointerToLetter = &letter;
Console.WriteLine($"Value of the `letter` variable: {letter}");
Console.WriteLine($"Address of the `letter` variable: {(long)pointerToLetter:X}");
*pointerToLetter = 'Z';
Console.WriteLine($"Value of the `letter` variable after update: {letter}");
}
// Output is similar to:
// Value of the `letter` variable: A
// Address of the `letter` variable: DCB977DDF4
// Value of the `letter` variable after update: Z
x->y
is equivalent to
(*x).y
unsafe
{
char* pointerToChars = stackalloc char[123];
In the preceding example, a stackalloc expression allocates a block of memory on the stack.
NOTE
The pointer element access operator doesn't check for out-of-bounds errors.
You cannot use [] for pointer element access with an expression of type void* .
You can also use the [] operator for array element or indexer access.
unsafe
{
const int Count = 3;
int[] numbers = new int[Count] { 10, 20, 30 };
fixed (int* pointerToFirst = &numbers[0])
{
int* pointerToLast = pointerToFirst + (Count - 1);
Pointer subtraction
For two pointers p1 and p2 of type T* , the expression p1 - p2 produces the difference between the addresses
given by p1 and p2 divided by sizeof(T) . The type of the result is long . That is, p1 - p2 is computed as
((long)(p1) - (long)(p2)) / sizeof(T) .
unsafe
{
int* numbers = stackalloc int[] { 0, 1, 2, 3, 4, 5 };
int* p1 = &numbers[1];
int* p2 = &numbers[5];
Console.WriteLine(p2 - p1); // output: 4
}
The following example demonstrates the behavior of both postfix and prefix increment operators:
unsafe
{
int* numbers = stackalloc int[] { 0, 1, 2 };
int* p1 = &numbers[0];
int* p2 = p1;
Console.WriteLine($"Before operation: p1 - {(long)p1}, p2 - {(long)p2}");
Console.WriteLine($"Postfix increment of p1: {(long)(p1++)}");
Console.WriteLine($"Prefix increment of p2: {(long)(++p2)}");
Console.WriteLine($"After operation: p1 - {(long)p1}, p2 - {(long)p2}");
}
// Output is similar to
// Before operation: p1 - 816489946512, p2 - 816489946512
// Postfix increment of p1: 816489946512
// Prefix increment of p2: 816489946516
// After operation: p1 - 816489946516, p2 - 816489946516
For information about the behavior of those operators for operands of other types, see the Equality operators and
Comparison operators articles.
Operator precedence
The following list orders pointer related operators starting from the highest precedence to the lowest:
Postfix increment x++ and decrement x-- operators and the -> and [] operators
Prefix increment ++x and decrement --x operators and the & and * operators
Additive + and - operators
Comparison < , > , <= , and >= operators
Equality == and != operators
Operator overloadability
A user-defined type cannot overload the pointer related operators & , * , -> , and [] .
C# language specification
For more information, see the following sections of the C# language specification:
Fixed and moveable variables
The address-of operator
Pointer indirection
Pointer member access
Pointer element access
Pointer arithmetic
Pointer increment and decrement
Pointer comparison
See also
C# reference
C# operators and expressions
Pointer types
unsafe keyword
fixed keyword
stackalloc
sizeof operator
Assignment operators (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
The assignment operator = assigns the value of its right-hand operand to a variable, a property, or an indexer
element given by its left-hand operand. The result of an assignment expression is the value assigned to the left-
hand operand. The type of the right-hand operand must be the same as the type of the left-hand operand or
implicitly convertible to it.
The assignment operator = is right-associative, that is, an expression of the form
a = b = c
is evaluated as
a = (b = c)
The following example demonstrates the usage of the assignment operator with a local variable, a property, and
an indexer element as its left-hand operand:
Console.WriteLine(numbers.Capacity);
numbers.Capacity = 100;
Console.WriteLine(numbers.Capacity);
// Output:
// 4
// 100
int newFirstElement;
double originalFirstElement = numbers[0];
newFirstElement = 5;
numbers[0] = newFirstElement;
Console.WriteLine(originalFirstElement);
Console.WriteLine(numbers[0]);
// Output:
// 1
// 5
In the case of the ref assignment operator, the both of its operands must be of the same type.
Compound assignment
For a binary operator op , a compound assignment expression of the form
x op= y
is equivalent to
x = x op y
Null-coalescing assignment
Beginning with C# 8.0, you can use the null-coalescing assignment operator ??= to assign the value of its right-
hand operand to its left-hand operand only if the left-hand operand evaluates to null . For more information, see
the ?? and ??= operators article.
Operator overloadability
A user-defined type cannot overload the assignment operator. However, a user-defined type can define an implicit
conversion to another type. That way, the value of a user-defined type can be assigned to a variable, a property, or
an indexer element of another type. For more information, see User-defined conversion operators.
A user-defined type cannot explicitly overload a compound assignment operator. However, if a user-defined type
overloads a binary operator op , the op= operator, if it exists, is also implicitly overloaded.
C# language specification
For more information, see the Assignment operators section of the C# language specification.
For more information about the ref assignment operator = ref , see the feature proposal note.
See also
C# reference
C# operators and expressions
ref keyword
Lambda expressions (C# reference)
9/3/2020 • 11 minutes to read • Edit Online
Use the lambda declaration operator => to separate the lambda's parameter list from its body. To create a
lambda expression, you specify input parameters (if any) on the left side of the lambda operator and an
expression or a statement block on the other side.
Any lambda expression can be converted to a delegate type. The delegate type to which a lambda
expression can be converted is defined by the types of its parameters and return value. If a lambda
expression doesn't return a value, it can be converted to one of the Action delegate types; otherwise, it can
be converted to one of the Func delegate types. For example, a lambda expression that has two
parameters and returns no value can be converted to an Action<T1,T2> delegate. A lambda expression that
has one parameter and returns a value can be converted to a Func<T,TResult> delegate. In the following
example, the lambda expression x => x * x , which specifies a parameter that's named x and returns the
value of x squared, is assigned to a variable of a delegate type:
Expression lambdas can also be converted to the expression tree types, as the following example shows:
You can use lambda expressions in any code that requires instances of delegate types or expression trees,
for example as an argument to the Task.Run(Action) method to pass the code that should be executed in
the background. You can also use lambda expressions when you write LINQ in C#, as the following example
shows:
int[] numbers = { 2, 3, 4, 5 };
var squaredNumbers = numbers.Select(x => x * x);
Console.WriteLine(string.Join(" ", squaredNumbers));
// Output:
// 4 9 16 25
When you use method-based syntax to call the Enumerable.Select method in the System.Linq.Enumerable
class, for example in LINQ to Objects and LINQ to XML, the parameter is a delegate type
System.Func<T,TResult>. When you call the Queryable.Select method in the System.Linq.Queryable class,
for example in LINQ to SQL, the parameter type is an expression tree type
Expression<Func<TSource,TResult>> . In both cases you can use the same lambda expression to specify the
parameter value. That makes the two Select calls to look similar although in fact the type of objects
created from the lambdas is different.
Expression lambdas
A lambda expression with an expression on the right side of the => operator is called an expression
lambda. Expression lambdas are used extensively in the construction of expression trees. An expression
lambda returns the result of the expression and takes the following basic form:
The parentheses are optional only if the lambda has one input parameter; otherwise they are required.
Specify zero input parameters with empty parentheses:
Sometimes it's impossible for the compiler to infer the input types. You can specify the types explicitly as
shown in the following example:
Input parameter types must be all explicit or all implicit; otherwise, a CS0748 compiler error occurs.
The body of an expression lambda can consist of a method call. However, if you are creating expression
trees that are evaluated outside the context of the .NET common language runtime, such as in SQL Server,
you should not use method calls in lambda expressions. The methods will have no meaning outside the
context of the .NET common language runtime.
Statement lambdas
A statement lambda resembles an expression lambda except that the statement(s) is enclosed in braces:
The body of a statement lambda can consist of any number of statements; however, in practice there are
typically no more than two or three.
Action<string> greet = name =>
{
string greeting = $"Hello {name}!";
Console.WriteLine(greeting);
};
greet("World");
// Output:
// Hello World!
Async lambdas
You can easily create lambda expressions and statements that incorporate asynchronous processing by
using the async and await keywords. For example, the following Windows Forms example contains an
event handler that calls and awaits an async method, ExampleMethodAsync .
You can add the same event handler by using an async lambda. To add this handler, add an async modifier
before the lambda parameter list, as the following example shows:
For more information about how to create and use async methods, see Asynchronous Programming with
async and await.
Func<(int, int, int), (int, int, int)> doubleThem = ns => (2 * ns.Item1, 2 * ns.Item2, 2 * ns.Item3);
var numbers = (2, 3, 4);
var doubledNumbers = doubleThem(numbers);
Console.WriteLine($"The set {numbers} doubled: {doubledNumbers}");
// Output:
// The set (2, 3, 4) doubled: (4, 6, 8)
Ordinarily, the fields of a tuple are named Item1 , Item2 , etc. You can, however, define a tuple with named
components, as the following example does.
Func<(int n1, int n2, int n3), (int, int, int)> doubleThem = ns => (2 * ns.n1, 2 * ns.n2, 2 * ns.n3);
var numbers = (2, 3, 4);
var doubledNumbers = doubleThem(numbers);
Console.WriteLine($"The set {numbers} doubled: {doubledNumbers}");
The delegate can be instantiated as a Func<int, bool> instance where int is an input parameter and
bool is the return value. The return value is always specified in the last type parameter. For example,
Func<int, string, bool> defines a delegate with two input parameters, int and string , and a return
type of bool . The following Func delegate, when it's invoked, returns Boolean value that indicates
whether the input parameter is equal to five:
You can also supply a lambda expression when the argument type is an Expression<TDelegate>, for
example in the standard query operators that are defined in the Queryable type. When you specify an
Expression<TDelegate> argument, the lambda is compiled to an expression tree.
The following example uses the Count standard query operator:
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int oddNumbers = numbers.Count(n => n % 2 == 1);
Console.WriteLine($"There are {oddNumbers} odd numbers in {string.Join(" ", numbers)}");
The compiler can infer the type of the input parameter, or you can also specify it explicitly. This particular
lambda expression counts those integers ( n ) which when divided by two have a remainder of 1.
The following example produces a sequence that contains all elements in the numbers array that precede
the 9, because that's the first number in the sequence that doesn't meet the condition:
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var firstNumbersLessThanSix = numbers.TakeWhile(n => n < 6);
Console.WriteLine(string.Join(" ", firstNumbersLessThanSix));
// Output:
// 5 4 1 3
The following example specifies multiple input parameters by enclosing them in parentheses. The method
returns all the elements in the numbers array until it encounters a number whose value is less than its
ordinal position in the array:
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);
Console.WriteLine(string.Join(" ", firstSmallNumbers));
// Output:
// 5 4
The general rules for type inference for lambdas are as follows:
The lambda must contain the same number of parameters as the delegate type.
Each input parameter in the lambda must be implicitly convertible to its corresponding delegate
parameter.
The return value of the lambda (if any) must be implicitly convertible to the delegate's return type.
Note that lambda expressions in themselves don't have a type because the common type system has no
intrinsic concept of "lambda expression." However, it's sometimes convenient to speak informally of the
"type" of a lambda expression. In these cases the type refers to the delegate type or Expression type to
which the lambda expression is converted.
updateCapturedLocalVariable = x =>
{
j = x;
bool result = j > input;
Console.WriteLine($"{j} is greater than {input}: {result}");
};
isEqualToCapturedLocalVariable = x => x == j;
int gameInput = 5;
game.Run(gameInput);
int anotherJ = 3;
game.updateCapturedLocalVariable(anotherJ);
C# language specification
For more information, see the Anonymous function expressions section of the C# language specification.
See also
C# reference
C# operators and expressions
LINQ (Language-Integrated Query)
Expression Trees
Local functions vs. lambda expressions
Visual Studio 2008 C# Samples (see LINQ Sample Queries files and XQuery program)
+ and += operators (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
The + and += operators are supported by the built-in integral and floating-point numeric types, the string type,
and delegate types.
For information about the arithmetic + operator, see the Unary plus and minus operators and Addition operator
+ sections of the Arithmetic operators article.
String concatenation
When one or both operands are of type string, the + operator concatenates the string representations of its
operands (the string representation of null is an empty string):
Beginning with C# 6, string interpolation provides a more convenient way to format strings:
Delegate combination
For operands of the same delegate type, the + operator returns a new delegate instance that, when invoked,
invokes the left-hand operand and then invokes the right-hand operand. If any of the operands is null , the +
operator returns the value of another operand (which also might be null ). The following example shows how
delegates can be combined with the + operator:
x += y
is equivalent to
x = x + y
int i = 5;
i += 9;
Console.WriteLine(i);
// Output: 14
Console.WriteLine();
printer += () => Console.Write("b");
printer(); // output: ab
You also use the += operator to specify an event handler method when you subscribe to an event. For more
information, see How to: subscribe to and unsubscribe from events.
Operator overloadability
A user-defined type can overload the + operator. When a binary + operator is overloaded, the += operator is
also implicitly overloaded. A user-defined type cannot explicitly overload the += operator.
C# language specification
For more information, see the Unary plus operator and Addition operator sections of the C# language
specification.
See also
C# reference
C# operators and expressions
How to concatenate multiple strings
Events
Arithmetic operators
- and -= operators
- and -= operators (C# reference)
9/3/2020 • 3 minutes to read • Edit Online
The - and -= operators are supported by the built-in integral and floating-point numeric types and delegate
types.
For information about the arithmetic - operator, see the Unary plus and minus operators and Subtraction
operator - sections of the Arithmetic operators article.
Delegate removal
For operands of the same delegate type, the - operator returns a delegate instance that is calculated as follows:
If both operands are non-null and the invocation list of the right-hand operand is a proper contiguous
sublist of the invocation list of the left-hand operand, the result of the operation is a new invocation list that
is obtained by removing the right-hand operand's entries from the invocation list of the left-hand operand.
If the right-hand operand's list matches multiple contiguous sublists in the left-hand operand's list, only the
right-most matching sublist is removed. If removal results in an empty list, the result is null .
var abbaab = a + b + b + a + a + b;
abbaab(); // output: abbaab
Console.WriteLine();
var ab = a + b;
var abba = abbaab - ab;
abba(); // output: abba
Console.WriteLine();
If the invocation list of the right-hand operand is not a proper contiguous sublist of the invocation list of the
left-hand operand, the result of the operation is the left-hand operand. For example, removing a delegate
that is not part of the multicast delegate does nothing and results in the unchanged multicast delegate.
Action a = () => Console.Write("a");
Action b = () => Console.Write("b");
var abbaab = a + b + b + a + a + b;
var aba = a + b + a;
The preceding example also demonstrates that during delegate removal delegate instances are compared.
For example, delegates that are produced from evaluation of identical lambda expressions are not equal.
For more information about delegate equality, see the Delegate equality operators section of the C#
language specification.
If the left-hand operand is null , the result of the operation is null . If the right-hand operand is null , the
result of the operation is the left-hand operand.
x -= y
is equivalent to
x = x - y
Console.WriteLine();
printer -= a;
printer(); // output: ab
You also use the -= operator to specify an event handler method to remove when you unsubscribe from an
event. For more information, see How to subscribe to and unsubscribe from events.
Operator overloadability
A user-defined type can overload the - operator. When a binary - operator is overloaded, the -= operator is
also implicitly overloaded. A user-defined type cannot explicitly overload the -= operator.
C# language specification
For more information, see the Unary minus operator and Subtraction operator sections of the C# language
specification.
See also
C# reference
C# operators and expressions
Events
Arithmetic operators
+ and += operators
?: operator (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
The conditional operator ?: , also known as the ternary conditional operator, evaluates a Boolean expression
and returns the result of one of the two expressions, depending on whether the Boolean expression evaluates to
true or false .
The condition expression must evaluate to true or false . If condition evaluates to true , the consequent
expression is evaluated, and its result becomes the result of the operation. If condition evaluates to false , the
alternative expression is evaluated, and its result becomes the result of the operation. Only consequent or
alternative is evaluated.
The type of consequent and alternative must be the same, or there must be an implicit conversion from one
type to the other.
The conditional operator is right-associative, that is, an expression of the form
a ? b : c ? d : e
is evaluated as
a ? b : (c ? d : e)
TIP
You can use the following mnemonic device to remember how the conditional operator is evaluated:
Console.WriteLine(sinc(0.1));
Console.WriteLine(sinc(0.0));
// Output:
// 0.998334166468282
// 1
Like the original conditional operator, the conditional ref expression evaluates only one of the two expressions:
either consequent or alternative .
In the case of the conditional ref expression, the type of consequent and alternative must be the same.
The following example demonstrates the usage of the conditional ref expression:
int index = 7;
ref int refValue = ref ((index < 5) ? ref smallArray[index] : ref largeArray[index - 5]);
refValue = 0;
index = 2;
((index < 5) ? ref smallArray[index] : ref largeArray[index - 5]) = 100;
string classify;
if (input >= 0)
{
classify = "nonnegative";
}
else
{
classify = "negative";
}
Operator overloadability
A user-defined type cannot overload the conditional operator.
C# language specification
For more information, see the Conditional operator section of the C# language specification.
For more information about the conditional ref expression, see the feature proposal note.
See also
C# reference
C# operators and expressions
if-else statement
?. and ?[] operators
?? and ??= operators
ref keyword
! (null-forgiving) operator (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
Available in C# 8.0 and later, the unary postfix ! operator is the null-forgiving operator. In an enabled nullable
annotation context, you use the null-forgiving operator to declare that expression x of a reference type isn't
null : x! . The unary prefix ! operator is the logical negation operator.
The null-forgiving operator has no effect at run time. It only affects the compiler's static flow analysis by changing
the null state of the expression. At run time, expression x! evaluates to the result of the underlying expression x
.
NOTE
In C# 8, the null-forgiving operator terminates the list of preceding null-conditional operations. For example, the expression
x?.y!.z is parsed as (x?.y)!.z . Due to this interpretation, z is evaluated even if x is null , which may result in a
NullReferenceException.
For more information about the nullable reference types feature, see Nullable reference types.
Examples
One of the use cases of the null-forgiving operator is in testing the argument validation logic. For example,
consider the following class:
#nullable enable
public class Person
{
public Person(string name) => Name = name ?? throw new ArgumentNullException(nameof(name));
Using the MSTest test framework, you can create the following test for the validation logic in the constructor:
[TestMethod, ExpectedException(typeof(ArgumentNullException))]
public void NullNameShouldThrowTest()
{
var person = new Person(null!);
}
Without the null-forgiving operator, the compiler generates the following warning for the preceding code:
Warning CS8625: Cannot convert null literal to non-nullable reference type . By using the null-forgiving operator,
you inform the compiler that passing null is expected and shouldn't be warned about.
You can also use the null-forgiving operator when you definitely know that an expression cannot be null but the
compiler doesn't manage to recognize that. In the following example, if the IsValid method returns true , its
argument is not null and you can safely dereference it:
public static void Main()
{
Person? p = Find("John");
if (IsValid(p))
{
Console.WriteLine($"Found {p!.Name}");
}
}
Without the null-forgiving operator, the compiler generates the following warning for the p.Name code:
Warning CS8602: Dereference of a possibly null reference .
If you can modify the IsValid method, you can use the NotNullWhen attribute to inform the compiler that an
argument of the IsValid method cannot be null when the method returns true :
In the preceding example, you don't need to use the null-forgiving operator because the compiler has enough
information to find out that p cannot be null inside the if statement. For more information about the
attributes that allow you to provide additional information about the null state of a variable, see Upgrade APIs
with attributes to define null expectations.
C# language specification
For more information, see The null-forgiving operator section of the draft of the nullable reference types
specification.
See also
C# reference
C# operators and expressions
Tutorial: Design with nullable reference types
?? and ??= operators (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
The null-coalescing operator ?? returns the value of its left-hand operand if it isn't null ; otherwise, it
evaluates the right-hand operand and returns its result. The ?? operator doesn't evaluate its right-hand
operand if the left-hand operand evaluates to non-null.
Available in C# 8.0 and later, the null-coalescing assignment operator ??= assigns the value of its right-hand
operand to its left-hand operand only if the left-hand operand evaluates to null . The ??= operator doesn't
evaluate its right-hand operand if the left-hand operand evaluates to non-null.
The left-hand operand of the ??= operator must be a variable, a property, or an indexer element.
In C# 7.3 and earlier, the type of the left-hand operand of the ?? operator must be either a reference type or a
nullable value type. Beginning with C# 8.0, that requirement is replaced with the following: the type of the left-
hand operand of the ?? and ??= operators cannot be a non-nullable value type. In particular, beginning with
C# 8.0, you can use the null-coalescing operators with unconstrained type parameters:
The null-coalescing operators are right-associative. That is, expressions of the form
a ?? b ?? c
d ??= e ??= f
are evaluated as
a ?? (b ?? c)
d ??= (e ??= f)
Examples
The ?? and ??= operators can be useful in the following scenarios:
In expressions with the null-conditional operators ?. and ?[], you can use the ?? operator to provide an
alternative expression to evaluate in case the result of the expression with null-conditional operations is
null :
double SumNumbers(List<double[]> setsOfNumbers, int indexOfSetToSum)
{
return setsOfNumbers?[indexOfSetToSum]?.Sum() ?? double.NaN;
}
When you work with nullable value types and need to provide a value of an underlying value type, use
the ?? operator to specify the value to provide in case a nullable type value is null :
int? a = null;
int b = a ?? -1;
Console.WriteLine(b); // output: -1
Use the Nullable<T>.GetValueOrDefault() method if the value to be used when a nullable type value is
null should be the default value of the underlying value type.
Beginning with C# 7.0, you can use a throw expression as the right-hand operand of the ?? operator to
make the argument-checking code more concise:
The preceding example also demonstrates how to use expression-bodied members to define a property.
Beginning with C# 8.0, you can use the ??= operator to replace the code of the form
if (variable is null)
{
variable = expression;
}
Operator overloadability
The operators ?? and ??= cannot be overloaded.
C# language specification
For more information about the ?? operator, see The null coalescing operator section of the C# language
specification.
For more information about the ??= operator, see the feature proposal note.
See also
C# reference
C# operators and expressions
?. and ?[] operators
?: operator
=> operator (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
The => token is supported in two forms: as the lambda operator and as a separator of a member name and the
member implementation in an expression body definition.
Lambda operator
In lambda expressions, the lambda operator => separates the input parameters on the left side from the lambda
body on the right side.
The following example uses the LINQ feature with method syntax to demonstrate the usage of lambda
expressions:
int[] numbers = { 4, 7, 10 };
int product = numbers.Aggregate(1, (interim, next) => interim * next);
Console.WriteLine(product); // output: 280
Input parameters of a lambda expression are strongly typed at compile time. When the compiler can infer the
types of input parameters, like in the preceding example, you may omit type declarations. If you need to specify
the type of input parameters, you must do that for each parameter, as the following example shows:
int[] numbers = { 4, 7, 10 };
int product = numbers.Aggregate(1, (int interim, int next) => interim * next);
Console.WriteLine(product); // output: 280
The following example shows how to define a lambda expression without input parameters:
where expression is a valid expression. The return type of expression must be implicitly convertible to the
member's return type. If the member's return type is void or if the member is a constructor, a finalizer, or a
property or indexer set accessor, expression must be a statement expression. Because the expression's result is
discarded, the return type of that expression can be any type.
The following example shows an expression body definition for a Person.ToString method:
Expression body definitions for methods, operators, and read-only properties are supported beginning with C# 6.
Expression body definitions for constructors, finalizers, and property and indexer accessors are supported
beginning with C# 7.0.
For more information, see Expression-bodied members.
Operator overloadability
The => operator cannot be overloaded.
C# language specification
For more information about the lambda operator, see the Anonymous function expressions section of the C#
language specification.
See also
C# reference
C# operators and expressions
:: operator (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
Use the namespace alias qualifier :: to access a member of an aliased namespace. You can use the :: qualifier
only between two identifiers. The left-hand identifier can be any of the following aliases:
A namespace alias created with a using alias directive:
An extern alias.
The global alias, which is the global namespace alias. The global namespace is the namespace that
contains namespaces and types that are not declared inside a named namespace. When used with the ::
qualifier, the global alias always references the global namespace, even if there is the user-defined
global namespace alias.
The following example uses the global alias to access the .NET System namespace, which is a member of
the global namespace. Without the global alias, the user-defined System namespace, which is a member
of the MyCompany.MyProduct namespace, would be accessed:
namespace MyCompany.MyProduct.System
{
class Program
{
static void Main() => global::System.Console.WriteLine("Using global alias");
}
class Console
{
string Suggestion => "Consider renaming this class";
}
}
NOTE
The global keyword is the global namespace alias only when it's the left-hand identifier of the :: qualifier.
You can also use the . token to access a member of an aliased namespace. However, the . token is also used
to access a type member. The :: qualifier ensures that its left-hand identifier always references a namespace
alias, even if there exists a type or namespace with the same name.
C# language specification
For more information, see the Namespace alias qualifiers section of the C# language specification.
See also
C# reference
C# operators and expressions
Using namespaces
await operator (C# reference)
9/3/2020 • 3 minutes to read • Edit Online
The await operator suspends evaluation of the enclosing async method until the asynchronous operation
represented by its operand completes. When the asynchronous operation completes, the await operator
returns the result of the operation, if any. When the await operator is applied to the operand that represents
an already completed operation, it returns the result of the operation immediately without suspension of the
enclosing method. The await operator doesn't block the thread that evaluates the async method. When the
await operator suspends the enclosing async method, the control returns to the caller of the method.
In the following example, the HttpClient.GetByteArrayAsync method returns the Task<byte[]> instance, which
represents an asynchronous operation that produces a byte array when it completes. Until the operation
completes, the await operator suspends the DownloadDocsMainPageAsync method. When
DownloadDocsMainPageAsync gets suspended, control is returned to the Main method, which is the caller of
DownloadDocsMainPageAsync . The Main method executes until it needs the result of the asynchronous
operation performed by the DownloadDocsMainPageAsync method. When GetByteArrayAsync gets all the bytes,
the rest of the DownloadDocsMainPageAsync method is evaluated. After that, the rest of the Main method is
evaluated.
using System;
using System.Net.Http;
using System.Threading.Tasks;
The preceding example uses the async Main method, which is possible beginning with C# 7.1. For more
information, see the await operator in the Main method section.
NOTE
For an introduction to asynchronous programming, see Asynchronous programming with async and await.
Asynchronous programming with async and await follows the task-based asynchronous pattern.
You can use the await operator only in a method, lambda expression, or anonymous method that is modified
by the async keyword. Within an async method, you can't use the await operator in the body of a
synchronous function, inside the block of a lock statement, and in an unsafe context.
The operand of the await operator is usually of one of the following .NET types: Task, Task<TResult>,
ValueTask, or ValueTask<TResult>. However, any awaitable expression can be the operand of the await
operator. For more information, see the Awaitable expressions section of the C# language specification.
The type of expression await t is TResult if the type of expression t is Task<TResult> or
ValueTask<TResult>. If the type of t is Task or ValueTask, the type of await t is void . In both cases, if t
throws an exception, await t rethrows the exception. For more information about exception handling, see
the Exceptions in async methods section of the try-catch statement article.
The async and await keywords are available in C# 5 and later.
C# language specification
For more information, see the Await expressions section of the C# language specification.
See also
C# reference
C# operators and expressions
async
Task asynchronous programming model
Asynchronous programming
Async in depth
Walkthrough: accessing the Web by using async and await
Tutorial: Generate and consume async streams using C# 8.0 and .NET Core 3.0
default value expressions (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
A default value expression produces the default value of a type. There are two kinds of default value expressions:
the default operator call and a default literal.
You also use the default keyword as the default case label within a switch statement.
default operator
The argument to the default operator must be the name of a type or a type parameter, as the following example
shows:
Console.WriteLine(default(int)); // output: 0
Console.WriteLine(default(object) is null); // output: True
void DisplayDefaultOf<T>()
{
var val = default(T);
Console.WriteLine($"Default value of {typeof(T)} is {(val == null ? "null" : val.ToString())}.");
}
DisplayDefaultOf<int?>();
DisplayDefaultOf<System.Numerics.Complex>();
DisplayDefaultOf<System.Collections.Generic.List<int>>();
// Output:
// Default value of System.Nullable`1[System.Int32] is null.
// Default value of System.Numerics.Complex is (0, 0).
// Default value of System.Collections.Generic.List`1[System.Int32] is null.
default literal
Beginning with C# 7.1, you can use the default literal to produce the default value of a type when the compiler
can infer the expression type. The default literal expression produces the same value as the default(T)
expression where T is the inferred type. You can use the default literal in any of the following cases:
In the assignment or initialization of a variable.
In the declaration of the default value for an optional method parameter.
In a method call to provide an argument value.
In a return statement or as an expression in an expression-bodied member.
The following example shows the usage of the default literal:
T[] InitializeArray<T>(int length, T initialValue = default)
{
if (length < 0)
{
throw new ArgumentOutOfRangeException(nameof(length), "Array length must be nonnegative.");
}
Display(InitializeArray<int>(3)); // output: [ 0, 0, 0 ]
Display(InitializeArray<bool>(4, default)); // output: [ False, False, False, False ]
C# language specification
For more information, see the Default value expressions section of the C# language specification.
For more information about the default literal, see the feature proposal note.
See also
C# reference
C# operators and expressions
Default values of C# types
Generics in .NET
delegate operator (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
The delegate operator creates an anonymous method that can be converted to a delegate type:
NOTE
Beginning with C# 3, lambda expressions provide a more concise and expressive way to create an anonymous function. Use
the => operator to construct a lambda expression:
For more information about features of lambda expressions, for example, capturing outer variables, see Lambda
expressions.
When you use the delegate operator, you might omit the parameter list. If you do that, the created anonymous
method can be converted to a delegate type with any list of parameters, as the following example shows:
// Output:
// Hello!
// This is world!
That's the only functionality of anonymous methods that is not supported by lambda expressions. In all other
cases, a lambda expression is a preferred way to write inline code.
You also use the delegate keyword to declare a delegate type.
C# language specification
For more information, see the Anonymous function expressions section of the C# language specification.
See also
C# reference
C# operators and expressions
=> operator
nameof expression (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
A nameof expression produces the name of a variable, type, or member as the string constant:
As the preceding example shows, in the case of a type and a namespace, the produced name is usually not fully
qualified.
In the case of verbatim identifiers, the @ character is not the part of a name, as the following example shows:
var @new = 5;
Console.WriteLine(nameof(@new)); // output: new
A nameof expression is evaluated at compile time and has no effect at run time.
You can use a nameof expression to make the argument-checking code more maintainable:
C# language specification
For more information, see the Nameof expressions section of the C# language specification.
See also
C# reference
C# operators and expressions
new operator (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
Constructor invocation
To create a new instance of a type, you typically invoke one of the constructors of that type using the new
operator:
You can use an object or collection initializer with the new operator to instantiate and initialize an object in
one statement, as the following example shows:
Array creation
You also use the new operator to create an array instance, as the following example shows:
Use array initialization syntax to create an array instance and populate it with elements in one statement.
The following example shows various ways how you can do that:
var a = new int[3] { 10, 20, 30 };
var b = new int[] { 10, 20, 30 };
var c = new[] { 10, 20, 30 };
Console.WriteLine(c.GetType()); // output: System.Int32[]
Operator overloadability
A user-defined type cannot overload the new operator.
C# language specification
For more information, see The new operator section of the C# language specification.
See also
C# reference
C# operators and expressions
Object and collection initializers
sizeof operator (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
The sizeofoperator returns the number of bytes occupied by a variable of a given type. The argument to the
sizeof operator must be the name of an unmanaged type or a type parameter that is constrained to be an
unmanaged type.
The sizeof operator requires an unsafe context. However, the expressions presented in the following table are
evaluated in compile time to the corresponding constant values and don't require an unsafe context:
sizeof(sbyte) 1
sizeof(byte) 1
sizeof(short) 2
sizeof(ushort) 2
sizeof(int) 4
sizeof(uint) 4
sizeof(long) 8
sizeof(ulong) 8
sizeof(char) 2
sizeof(float) 4
sizeof(double) 8
sizeof(decimal) 16
sizeof(bool) 1
You also don't need to use an unsafe context when the operand of the sizeof operator is the name of an enum
type.
The following example demonstrates the usage of the sizeof operator:
using System;
unsafe
{
Console.WriteLine(sizeof(Point*)); // output: 8
}
}
The sizeof operator returns a number of bytes that would be allocated by the common language runtime in
managed memory. For struct types, that value includes any padding, as the preceding example demonstrates. The
result of the sizeof operator might differ from the result of the Marshal.SizeOf method, which returns the size of
a type in unmanaged memory.
C# language specification
For more information, see The sizeof operator section of the C# language specification.
See also
C# reference
C# operators and expressions
Pointer related operators
Pointer types
Memory and span-related types
Generics in .NET
stackalloc expression (C# reference)
9/3/2020 • 3 minutes to read • Edit Online
A stackalloc expression allocates a block of memory on the stack. A stack allocated memory block created
during the method execution is automatically discarded when that method returns. You cannot explicitly free
the memory allocated with stackalloc . A stack allocated memory block is not subject to garbage collection
and doesn't have to be pinned with a fixed statement.
You can assign the result of a stackalloc expression to a variable of one of the following types:
Beginning with C# 7.2, System.Span<T> or System.ReadOnlySpan<T>, as the following example shows:
int length = 3;
Span<int> numbers = stackalloc int[length];
for (var i = 0; i < length; i++)
{
numbers[i] = i;
}
You don't have to use an unsafe context when you assign a stack allocated memory block to a Span<T>
or ReadOnlySpan<T> variable.
When you work with those types, you can use a stackalloc expression in conditional or assignment
expressions, as the following example shows:
Beginning with C# 8.0, you can use a stackalloc expression inside other expressions whenever a
Span<T> or ReadOnlySpan<T> variable is allowed, as the following example shows:
NOTE
We recommend using Span<T> or ReadOnlySpan<T> types to work with stack allocated memory whenever
possible.
unsafe
{
int length = 3;
int* numbers = stackalloc int[length];
for (var i = 0; i < length; i++)
{
numbers[i] = i;
}
}
As the preceding example shows, you must use an unsafe context when you work with pointer types.
In the case of pointer types, you can use a stackalloc expression only in a local variable declaration to
initialize the variable.
The amount of memory available on the stack is limited. If you allocate too much memory on the stack, a
StackOverflowException is thrown. To avoid that, follow the rules below:
Limit the amount of memory you allocate with stackalloc :
Because the amount of memory available on the stack depends on the environment in which the code is
executed, be conservative when you define the actual limit value.
Avoid using stackalloc inside loops. Allocate the memory block outside a loop and reuse it inside the
loop.
The content of the newly allocated memory is undefined. You should initialize it before the use. For example,
you can use the Span<T>.Clear method that sets all the items to the default value of type T .
Beginning with C# 7.3, you can use array initializer syntax to define the content of the newly allocated memory.
The following example demonstrates various ways to do that:
In expression stackalloc T[E] , T must be an unmanaged type and E must evaluate to a non-negative int
value.
Security
The use of stackalloc automatically enables buffer overrun detection features in the common language
runtime (CLR). If a buffer overrun is detected, the process is terminated as quickly as possible to minimize the
chance that malicious code is executed.
C# language specification
For more information, see the Stack allocation section of the C# language specification and the Permit
stackalloc in nested contexts feature proposal note.
See also
C# reference
C# operators and expressions
Pointer related operators
Pointer types
Memory and span-related types
Dos and Don'ts of stackalloc
switch expression (C# reference)
9/3/2020 • 3 minutes to read • Edit Online
This article covers the switch expression, introduced in C# 8.0. For information on the switch statement, see the
article on the switch statement in the statements section.
Basic example
The switch expression provides for switch -like semantics in an expression context. It provides a concise syntax
when the switch arms produce a value. The following example shows the structure of a switch expression. It
translates values from an enum representing visual directions in an online map to the corresponding cardinal
direction:
Patterns can be recursive, where a pattern tests a type, and if that type matches, the pattern matches one or more
property values on the range expression. You can use recursive patterns to extend the preceding example. You add
switch expression arms for arrays that have fewer than 3 elements. Recursive patterns are shown in the following
example:
Recursive patterns can examine properties of the range expression, but can't execute arbitrary code. You can use a
case guard, specified in a when clause, to provide similar checks for other sequence types:
Finally, you can add the _ pattern and the null pattern to catch arguments that aren't processed by any other
switch expression arm. That makes the switch expression exhaustive, meaning any possible value of the range
expression is handled. The following example adds those expression arms:
public static T ExhaustiveExample<T>(IEnumerable<T> sequence) =>
sequence switch
{
System.Array { Length : 0} => default(T),
System.Array { Length : 1} array => (T)array.GetValue(0),
System.Array { Length : 2} array => (T)array.GetValue(1),
System.Array array => (T)array.GetValue(2),
IEnumerable<T> list
when !list.Any() => default(T),
IEnumerable<T> list
when list.Count() < 3 => list.Last(),
IList<T> list => list[2],
null => throw new ArgumentNullException(nameof(sequence)),
_ => sequence.Skip(2).First(),
};
The preceding example adds a null pattern, and changes the IEnumerable<T> type pattern to a _ pattern. The
null pattern provides a null check as a switch expression arm. The expression for that arm throws an
ArgumentNullException. The _ pattern matches all inputs that haven't been matched by previous arms. It must
come after the null check, or it would match null inputs.
You can read more in the C# language spec proposal for recursive patterns.
See also
C# reference
C# operators and expressions
Pattern matching
true and false operators (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
The true operator returns the bool value true to indicate that its operand is definitely true. The false operator
returns the bool value true to indicate that its operand is definitely false. The true and false operators are
not guaranteed to complement each other. That is, both the true and false operator might return the bool
value false for the same operand. If a type defines one of the two operators, it must also define another
operator.
TIP
Use the bool? type, if you need to support the three-valued logic (for example, when you work with databases that
support a three-valued Boolean type). C# provides the & and | operators that support the three-valued logic with the
bool? operands. For more information, see the Nullable Boolean logical operators section of the Boolean logical operators
article.
Boolean expressions
A type with the defined true operator can be the type of a result of a controlling conditional expression in the if,
do, while, and for statements and in the conditional operator ?: . For more information, see the Boolean
expressions section of the C# language specification.
Example
The following example presents the type that defines both true and false operators. The type also overloads
the logical AND operator & in such a way that the && operator also can be evaluated for the operands of that
type.
using System;
if (x == Yellow || y == Yellow)
{
return Yellow;
}
return Green;
}
public override bool Equals(object obj) => obj is LaunchStatus other && this == other;
public override int GetHashCode() => status;
}
Notice the short-circuiting behavior of the && operator. When the GetFuelLaunchStatus method returns
LaunchStatus.Red , the right-hand operand of the && operator is not evaluated. That is because LaunchStatus.Red
is definitely false. Then the result of the logical AND doesn't depend on the value of the right-hand operand. The
output of the example is as follows:
Getting fuel launch status...
Wait!
See also
C# reference
C# operators and expressions
Operator overloading (C# reference)
9/3/2020 • 3 minutes to read • Edit Online
A user-defined type can overload a predefined C# operator. That is, a type can provide the custom
implementation of an operation in case one or both of the operands are of that type. The Overloadable
operators section shows which C# operators can be overloaded.
Use the operator keyword to declare an operator. An operator declaration must satisfy the following rules:
It includes both a public and a static modifier.
A unary operator has one input parameter. A binary operator has two input parameters. In each case, at
least one parameter must have type T or T? where T is the type that contains the operator declaration.
The following example defines a simplified structure to represent a rational number. The structure overloads
some of the arithmetic operators:
using System;
You could extend the preceding example by defining an implicit conversion from int to Fraction . Then,
overloaded operators would support arguments of those two types. That is, it would become possible to add
an integer to a fraction and obtain a fraction as a result.
You also use the operator keyword to define a custom type conversion. For more information, see User-
defined conversion operators.
Overloadable operators
The following table provides information about overloadability of C# operators:
O P ERATO RS O VERLO A DA B IL IT Y
+x, -x, !x, ~x, ++, --, true, false These unary operators can be overloaded.
(T)x The cast operator cannot be overloaded, but you can define
custom type conversions that can be performed by a cast
expression. For more information, see User-defined
conversion operators.
+=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>= Compound assignment operators cannot be explicitly
overloaded. However, when you overload a binary operator,
the corresponding compound assignment operator, if any,
is also implicitly overloaded. For example, += is evaluated
using + , which can be overloaded.
^x, x = y, x.y, x?.y , c ? t : f, x ?? y, x ??= y, x..y, x->y, =>, These operators cannot be overloaded.
f(x), as, await, checked, unchecked, default, delegate, is,
nameof, new, sizeof, stackalloc, switch, typeof
NOTE
The comparison operators must be overloaded in pairs. That is, if either operator of a pair is overloaded, the other
operator must be overloaded as well. Such pairs are as follows:
== and != operators
< and > operators
<= and >= operators
C# language specification
For more information, see the following sections of the C# language specification:
Operator overloading
Operators
See also
C# reference
C# operators and expressions
User-defined conversion operators
Design guidelines - Operator overloads
Design guidelines - Equality operators
Why are overloaded operators always static in C#?
C# Special Characters
9/3/2020 • 2 minutes to read • Edit Online
Special characters are predefined, contextual characters that modify the program element (a literal string, an
identifier, or an attribute name) to which they are prepended. C# supports the following special characters:
@, the verbatim identifier character.
$, the interpolated string character.
See also
C# Reference
C# Programming Guide
$ - string interpolation (C# reference)
4/21/2020 • 4 minutes to read • Edit Online
The $ special character identifies a string literal as an interpolated string. An interpolated string is a string
literal that might contain interpolation expressions. When an interpolated string is resolved to a result string,
items with interpolation expressions are replaced by the string representations of the expression results. This
feature is available starting with C# 6.
String interpolation provides a more readable and convenient syntax to create formatted strings than a string
composite formatting feature. The following example uses both features to produce the same output:
// Composite formatting:
Console.WriteLine("Hello, {0}! Today is {1}, it's {2:HH:mm} now.", name, date.DayOfWeek, date);
// String interpolation:
Console.WriteLine($"Hello, {name}! Today is {date.DayOfWeek}, it's {date:HH:mm} now.");
// Both calls produce the same output that is similar to:
// Hello, Mark! Today is Wednesday, it's 19:40 now.
{<interpolationExpression>[,<alignment>][:<formatString>]}
Elements in square brackets are optional. The following table describes each element:
EL EM EN T DESC RIP T IO N
Special characters
To include a brace, "{" or "}", in the text produced by an interpolated string, use two braces, "{{" or "}}". For
more information, see Escaping Braces.
As the colon (":") has special meaning in an interpolation expression item, in order to use a conditional
operator in an interpolation expression, enclose that expression in parentheses.
The following example shows how to include a brace in a result string and how to use a conditional operator
in an interpolation expression:
An interpolated verbatim string starts with the $ character followed by the @ character. For more
information about verbatim strings, see the string and verbatim identifier topics.
NOTE
Starting with C# 8.0, you can use the $ and @ tokens in any order: both $@"..." and @$"..." are valid
interpolated verbatim strings. In earlier C# versions, the $ token must appear before the @ token.
System.Globalization.CultureInfo.CurrentCulture = System.Globalization.CultureInfo.GetCultureInfo("nl-
NL");
string messageInCurrentCulture = message.ToString();
Console.WriteLine($"{System.Globalization.CultureInfo.CurrentCulture,-10} {messageInCurrentCulture}");
Console.WriteLine($"{specificCulture,-10} {messageInSpecificCulture}");
Console.WriteLine($"{"Invariant",-10} {messageInInvariantCulture}");
// Expected output is:
// nl-NL The speed of light is 299.792,458 km/s.
// en-IN The speed of light is 2,99,792.458 km/s.
// Invariant The speed of light is 299,792.458 km/s.
Additional resources
If you are new to string interpolation, see the String interpolation in C# interactive tutorial. You can also check
another String interpolation in C# tutorial that demonstrates how to use interpolated strings to produce
formatted strings.
C# language specification
For more information, see the Interpolated strings section of the C# language specification.
See also
C# reference
C# special characters
Strings
Standard numeric format strings
Composite formatting
String.Format
@ (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
The @ special character serves as a verbatim identifier. It can be used in the following ways:
1. To enable C# keywords to be used as identifiers. The @ character prefixes a code element that the compiler
is to interpret as an identifier rather than a C# keyword. The following example uses the @ character to
define an identifier named for that it uses in a for loop.
2. To indicate that a string literal is to be interpreted verbatim. The @ character in this instance defines a
verbatim string literal. Simple escape sequences (such as "\\" for a backslash), hexadecimal escape
sequences (such as "\x0041" for an uppercase A), and Unicode escape sequences (such as "\u0041" for
an uppercase A) are interpreted literally. Only a quote escape sequence ( "" ) is not interpreted literally; it
produces one double quotation mark. Additionally, in case of a verbatim interpolated string brace escape
sequences ( {{ and }} ) are not interpreted literally; they produce single brace characters. The following
example defines two identical file paths, one by using a regular string literal and the other by using a
verbatim string literal. This is one of the more common uses of verbatim string literals.
Console.WriteLine(filename1);
Console.WriteLine(filename2);
// The example displays the following output:
// c:\documents\files\u0066.txt
// c:\documents\files\u0066.txt
The following example illustrates the effect of defining a regular string literal and a verbatim string literal
that contain identical character sequences.
Console.WriteLine(s1);
Console.WriteLine(s2);
// The example displays the following output:
// He said, "This is the last chance!"
// He said, "This is the last \u0063hance\x0021"
3. To enable the compiler to distinguish between attributes in cases of a naming conflict. An attribute is a class
that derives from Attribute. Its type name typically includes the suffix Attribute , although the compiler
does not enforce this convention. The attribute can then be referenced in code either by its full type name
(for example, [InfoAttribute] or its shortened name (for example, [Info] ). However, a naming conflict
occurs if two shortened attribute type names are identical, and one type name includes the Attribute
suffix but the other does not. For example, the following code fails to compile because the compiler cannot
determine whether the Info or InfoAttribute attribute is applied to the Example class. See CS1614 for
more information.
using System;
[AttributeUsage(AttributeTargets.Class)]
public class Info : Attribute
{
private string information;
[AttributeUsage(AttributeTargets.Method)]
public class InfoAttribute : Attribute
{
private string information;
[Info("A simple executable.")] // Generates compiler error CS1614. Ambiguous Info and InfoAttribute.
// Prepend '@' to select 'Info'. Specify the full name 'InfoAttribute' to select it.
public class Example
{
[InfoAttribute("The entry point.")]
public static void Main()
{
}
}
See also
C# Reference
C# Programming Guide
C# Special Characters
Reserved attributes: Assembly level attributes
4/15/2020 • 2 minutes to read • Edit Online
Most attributes are applied to specific language elements such as classes or methods; however, some attributes are
global—they apply to an entire assembly or module. For example, the AssemblyVersionAttribute attribute can be
used to embed version information into an assembly, like this:
[assembly: AssemblyVersion("1.0.0.0")]
Global attributes appear in the source code after any top level using directives and before any type, module, or
namespace declarations. Global attributes can appear in multiple source files, but the files must be compiled in a
single compilation pass. Visual Studio adds global attributes to the AssemblyInfo.cs file in .NET Framework
projects. These attributes aren't added to .NET Core projects.
Assembly attributes are values that provide information about an assembly. They fall into the following categories:
Assembly identity attributes
Informational attributes
Assembly manifest attributes
AT T RIB UT E P URP O SE
Informational attributes
You use informational attributes to provide additional company or product information for an assembly. The
following table shows the informational attributes defined in the System.Reflection namespace.
AT T RIB UT E P URP O SE
AssemblyFileVersionAttribute Sets a specific version number for the Win32 file version
resource.
AT T RIB UT E P URP O SE
These attributes can be applied to elements in your code. They add semantic meaning to those elements. The
compiler uses those semantic meanings to alter its output and report possible mistakes by developers using your
code.
Conditional attribute
The Conditional attribute makes the execution of a method dependent on a preprocessing identifier. The
Conditional attribute is an alias for ConditionalAttribute, and can be applied to a method or an attribute class.
In the following example, Conditional is applied to a method to enable or disable the display of program-specific
diagnostic information:
#define TRACE_ON
using System;
using System.Diagnostics;
namespace AttributeExamples
{
public class Trace
{
[Conditional("TRACE_ON")]
public static void Msg(string msg)
{
Console.WriteLine(msg);
}
}
If the TRACE_ON identifier isn't defined, the trace output isn't displayed. Explore for yourself in the interactive
window.
The Conditional attribute is often used with the DEBUG identifier to enable trace and logging features for debug
builds but not in release builds, as shown in the following example:
[Conditional("DEBUG")]
static void DebugMethod()
{
}
When a method marked conditional is called, the presence or absence of the specified preprocessing symbol
determines whether the call is included or omitted. If the symbol is defined, the call is included; otherwise, the call
is omitted. A conditional method must be a method in a class or struct declaration and must have a void return
type. Using Conditional is cleaner, more elegant, and less error-prone than enclosing methods inside #if…#endif
blocks.
If a method has multiple Conditional attributes, a call to the method is included if at one or more conditional
symbols is defined (the symbols are logically linked together by using the OR operator). In the following example,
the presence of either A or B results in a method call:
[Conditional("A"), Conditional("B")]
static void DoIfAorB()
{
// ...
}
[Conditional("DEBUG")]
public class DocumentationAttribute : System.Attribute
{
string text;
class SampleClass
{
// This attribute will only be included if DEBUG is defined.
[Documentation("This method displays an integer.")]
static void DoWork(int i)
{
System.Console.WriteLine(i.ToString());
}
}
Obsolete attribute
The Obsolete attribute marks a code element as no longer recommended for use. Use of an entity marked
obsolete generates a warning or an error. The Obsolete attribute is a single-use attribute and can be applied to
any entity that allows attributes. Obsolete is an alias for ObsoleteAttribute.
In the following example the Obsolete attribute is applied to class A and to method B.OldMethod . Because the
second argument of the attribute constructor applied to B.OldMethod is set to true , this method will cause a
compiler error, whereas using class A will just produce a warning. Calling B.NewMethod , however, produces no
warning or error. For example, when you use it with the previous definitions, the following code generates two
warnings and one error:
using System;
namespace AttributeExamples
{
[Obsolete("use class B")]
public class A
{
public void Method() { }
}
public class B
{
[Obsolete("use NewMethod", true)]
public void OldMethod() { }
The string provided as the first argument to the attribute constructor will be displayed as part of the warning or
error. Two warnings for class A are generated: one for the declaration of the class reference, and one for the class
constructor. The Obsolete attribute can be used without arguments, but including an explanation what to use
instead is recommended.
AttributeUsage attribute
The AttributeUsage attribute determines how a custom attribute class can be used. AttributeUsageAttribute is an
attribute you apply to custom attribute definitions. The AttributeUsage attribute enables you to control:
Which program elements attribute may be applied to. Unless you restrict its usage, an attribute may be applied
to any of the following program elements:
assembly
module
field
event
method
param
property
return
type
Whether an attribute can be applied to a single program element multiple times.
Whether attributes are inherited by derived classes.
The default settings look like the following example when applied explicitly:
[AttributeUsage(AttributeTargets.All,
AllowMultiple = false,
Inherited = true)]
class NewAttribute : Attribute { }
In this example, the NewAttribute class can be applied to any supported program element. But it can be applied
only once to each entity. The attribute is inherited by derived classes when applied to a base class.
The AllowMultiple and Inherited arguments are optional, so the following code has the same effect:
[AttributeUsage(AttributeTargets.All)]
class NewAttribute : Attribute { }
The first AttributeUsageAttribute argument must be one or more elements of the AttributeTargets enumeration.
Multiple target types can be linked together with the OR operator, like the following example shows:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
class NewPropertyOrFieldAttribute : Attribute { }
Beginning in C# 7.3, attributes can be applied to either the property or the backing field for an auto-implemented
property. The attribute applies to the property, unless you specify the field specifier on the attribute. Both are
shown in the following example:
class MyClass
{
// Attribute attached to property:
[NewPropertyOrField]
public string Name { get; set; }
If the AllowMultiple argument is true , then the resulting attribute can be applied more than once to a single
entity, as shown in the following example:
[MultiUse]
[MultiUse]
class Class1 { }
[MultiUse, MultiUse]
class Class2 { }
In this case, MultiUseAttribute can be applied repeatedly because AllowMultiple is set to true . Both formats
shown for applying multiple attributes are valid.
If Inherited is false , then the attribute isn't inherited by classes derived from an attributed class. For example:
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
class NonInheritedAttribute : Attribute { }
[NonInherited]
class BClass { }
See also
Attribute
System.Reflection
Attributes
Reflection
Reserved attributes: Determine caller information
4/15/2020 • 2 minutes to read • Edit Online
Using info attributes, you obtain information about the caller to a method. You obtain the file path of the source
code, the line number in the source code, and the member name of the caller. To obtain member caller information,
you use attributes that are applied to optional parameters. Each optional parameter specifies a default value. The
following table lists the Caller Info attributes that are defined in the System.Runtime.CompilerServices namespace:
This information helps you write tracing, debugging, and create diagnostic tools. The following example shows
how to use caller info attributes. On each call to the TraceMessage method, the caller information is substituted as
arguments to the optional parameters.
// Sample Output:
// message: Something happened.
// member name: DoProcessing
// source file path: c:\Visual Studio Projects\CallerInfoCS\CallerInfoCS\Form1.cs
// source line number: 31
You specify an explicit default value for each optional parameter. You can't apply caller info attributes to parameters
that aren't specified as optional. The caller info attributes don't make a parameter optional. Instead, they affect the
default value that's passed in when the argument is omitted. Caller info values are emitted as literals into the
Intermediate Language (IL) at compile time. Unlike the results of the StackTrace property for exceptions, the results
aren't affected by obfuscation. You can explicitly supply the optional arguments to control the caller information or
to hide caller information.
Member names
You can use the CallerMemberName attribute to avoid specifying the member name as a String argument to the
called method. By using this technique, you avoid the problem that Rename Refactoring doesn't change the
String values. This benefit is especially useful for the following tasks:
C A L L S O C C UR W IT H IN M EM B ER N A M E RESULT
Method, property, or event The name of the method, property, or event from which the
call originated.
User-defined operators or conversions The generated name for the member, for example,
"op_Addition".
Attribute constructor The name of the method or property to which the attribute is
applied. If the attribute is any element within a member (such
as a parameter, a return value, or a generic type parameter),
this result is the name of the member that's associated with
that element.
No containing member (for example, assembly-level or The default value of the optional parameter.
attributes that are applied to types)
See also
Named and Optional Arguments
System.Reflection
Attribute
Attributes
Reserved attributes contribute to the compiler's null
state static analysis
4/23/2020 • 13 minutes to read • Edit Online
In a nullable context, the compiler performs static analysis of code to determine the null state of all reference type
variables:
not null: Static analysis determined that the variable is assigned to a non-null value.
maybe null: Static analysis cannot determine that a variable is assigned a non-null value.
You can apply a number of attributes that provide information to the compiler about the semantics of your APIs.
That information helps the compiler perform static analysis and determine when a variable is not null. This article
provides a brief description of each of those attributes and how to use them. All the examples assume C# 8.0 or
newer, and the code is in a nullable context.
Let's start with a familiar example. Imagine your library has the following API to retrieve a resource string:
The preceding example follows the familiar Try* pattern in .NET. There are two reference arguments for this API:
the key and the message parameter. This API has the following rules relating to the nullness of these arguments:
Callers shouldn't pass null as the argument for key .
Callers can pass a variable whose value is null as the argument for message .
If the TryGetMessage method returns true , the value of message isn't null. If the return value is false, the
value of message (and its null state) is null.
The rule for key can be expressed by the variable type: key should be a non-nullable reference type. The
message parameter is more complex. It allows null as the argument, but guarantees that, on success, that out
argument isn't null. For these scenarios, you need a richer vocabulary to describe the expectations.
Several attributes have been added to express additional information about the null state of variables. All code
you wrote before C# 8 introduced nullable reference types was null oblivious. That means any reference type
variable may be null, but null checks aren't required. Once your code is nullable aware, those rules change.
Reference types should never be the null value, and nullable reference types must be checked against null
before being dereferenced.
The rules for your APIs are likely more complicated, as you saw with the TryGetValue API scenario. Many of your
APIs have more complex rules for when variables can or can't be null . In these cases, you'll use one of the
following attributes to express those rules:
AllowNull: A non-nullable input argument may be null.
DisallowNull: A nullable input argument should never be null.
MaybeNull: A non-nullable return value may be null.
NotNull: A nullable return value will never be null.
MaybeNullWhen: A non-nullable input argument may be null when the method returns the specified bool
value.
NotNullWhen: A nullable input argument will not be null when the method returns the specified bool value.
NotNullIfNotNull: A return value isn't null if the argument for the specified parameter isn't null.
DoesNotReturn: A method never returns. In other words, it always throws an exception.
DoesNotReturnIf: This method never returns if the associated bool parameter has the specified value.
The preceding descriptions are a quick reference to what each attribute does. Each following section describes the
behavior and meaning more thoroughly.
Adding these attributes gives the compiler more information about the rules for your API. When calling code is
compiled in a nullable enabled context, the compiler will warn callers when they violate those rules. These
attributes don't enable additional checks on your implementation.
When you compile the preceding code in a nullable oblivious context, everything is fine. Once you enable nullable
reference types, the ScreenName property becomes a non-nullable reference. That's correct for the get accessor:
it never returns null . Callers don't need to check the returned property for null . But now setting the property
to null generates a warning. In order to continue to support this type of code, you add the
System.Diagnostics.CodeAnalysis.AllowNullAttribute attribute to the property, as shown in the following code:
[AllowNull]
public string ScreenName
{
get => screenName;
set => screenName = value ?? GenerateRandomScreenName();
}
private string screenName = GenerateRandomScreenName();
You may need to add a using directive for System.Diagnostics.CodeAnalysis to use this and other attributes
discussed in this article. The attribute is applied to the property, not the set accessor. The AllowNull attribute
specifies pre-conditions, and only applies to inputs. The get accessor has a return value, but no input arguments.
Therefore, the AllowNull attribute only applies to the set accessor.
The preceding example demonstrates what to look for when adding the AllowNull attribute on an argument:
1. The general contract for that variable is that it shouldn't be null , so you want a non-nullable reference type.
2. There are scenarios for the input variable to be null , though they aren't the most common usage.
Most often you'll need this attribute for properties, or in , out , and ref arguments. The AllowNull attribute is
the best choice when a variable is typically non-null, but you need to allow null as a precondition.
Contrast that with scenarios for using DisallowNull : You use this attribute to specify that an input variable of a
nullable reference type shouldn't be null . Consider a property where null is the default value, but clients can
only set it to a non-null value. Consider the following code:
public string ReviewComment
{
get => _comment;
set => _comment = value ?? throw new ArgumentNullException(nameof(value), "Cannot set to null");
}
string _comment;
The preceding code is the best way to express your design that the ReviewComment could be null , but can't be set
to null . Once this code is nullable aware, you can express this concept more clearly to callers using the
System.Diagnostics.CodeAnalysis.DisallowNullAttribute:
[DisallowNull]
public string? ReviewComment
{
get => _comment;
set => _comment = value ?? throw new ArgumentNullException(nameof(value), "Cannot set to null");
}
string? _comment;
In a nullable context, the ReviewComment get accessor could return the default value of null . The compiler warns
that it must be checked before access. Furthermore, it warns callers that, even though it could be null , callers
shouldn't explicitly set it to null . The DisallowNull attribute also specifies a pre-condition, it does not affect the
get accessor. You use the DisallowNull attribute when you observe these characteristics about:
1. The variable could be null in core scenarios, often when first instantiated.
2. The variable shouldn't be explicitly set to null .
These situations are common in code that was originally null oblivious. It may be that object properties are set in
two distinct initialization operations. It may be that some properties are set only after some asynchronous work
has completed.
The AllowNull and DisallowNull attributes enable you to specify that preconditions on variables may not match
the nullable annotations on those variables. These provide more detail about the characteristics of your API. This
additional information helps callers use your API correctly. Remember you specify preconditions using the
following attributes:
AllowNull: A non-nullable input argument may be null.
DisallowNull: A nullable input argument should never be null.
You've likely written a method like this to return null when the name sought wasn't found. The null clearly
indicates that the record wasn't found. In this example, you'd likely change the return type from Customer to
Customer? . Declaring the return value as a nullable reference type specifies the intent of this API clearly.
For reasons covered under Generic definitions and nullability that technique does not work with generic methods.
You may have a generic method that follows a similar pattern:
[return: MaybeNull]
public T Find<T>(IEnumerable<T> sequence, Func<T, bool> match)
The preceding code informs callers that the contract implies a non-nullable type, but the return value may actually
be null. Use the MaybeNull attribute when your API should be a non-nullable type, typically a generic type
parameter, but there may be instances where null would be returned.
You can also specify that a return value or an out or ref argument isn't null even though the type is a nullable
reference type. Consider a method that ensures an array is large enough to hold a number of elements. If the
input argument doesn't have capacity, the routine would allocate a new array and copy all the existing elements
into it. If the input argument is null , the routine would allocate new storage. If there's sufficient capacity, the
routine does nothing:
After enabling null reference types, you want to ensure that the preceding code compiles without warnings. When
the method returns, the storage argument is guaranteed to be not null. However, it's acceptable to call
EnsureCapacity with a null reference. You can make storage a nullable reference type, and add the NotNull
post-condition to the parameter declaration:
The preceding code expresses the existing contract clearly: Callers can pass a variable with the null value, but the
return value is guaranteed to never be null. The NotNull attribute is most useful for ref and out arguments
where null may be passed as an argument, but that argument is guaranteed to be not null when the method
returns.
You specify unconditional postconditions using the following attributes:
MaybeNull: A non-nullable return value may be null.
NotNull: A nullable return value will never be null.
That informs the compiler that any code where the return value is false need not be null-checked. The addition
of the attribute informs the compiler's static analysis that IsNullOrEmpty performs the necessary null check: when
it returns false , the input argument is not null .
The String.IsNullOrEmpty(String) method will be annotated as shown above for .NET Core 3.0. You may have
similar methods in your codebase that check the state of objects for null values. The compiler won't recognize
custom null check methods, and you'll need to add the annotations yourself. When you add the attribute, the
compiler's static analysis knows when the tested variable has been null checked.
Another use for these attributes is the Try* pattern. The postconditions for ref and out variables are
communicated through the return value. Consider this method shown earlier:
The preceding method follows a typical .NET idiom: the return value indicates if message was set to the found
value or, if no message is found, to the default value. If the method returns true , the value of message isn't null;
otherwise, the method sets message to null.
You can communicate that idiom using the NotNullWhen attribute. When you update the signature for nullable
reference types, make message a string? and add an attribute:
In the preceding example, the value of message is known to be not null when TryGetMessage returns true . You
should annotate similar methods in your codebase in the same way: the arguments could be null , and are
known to be not null when the method returns true .
There's one final attribute you may also need. Sometimes the null state of a return value depends on the null state
of one or more input arguments. These methods will return a non-null value whenever certain input arguments
aren't null . To correctly annotate these methods, you use the NotNullIfNotNull attribute. Consider the following
method:
If the url argument isn't null, the output isn't null . Once nullable references are enabled, that signature works
correctly, provided your API never accepts a null input. However, if the input could be null, then return value could
also be null. Therefore, you could change the signature to the following code:
That also works, but will often force callers to implement extra null checks. The contract is that the return value
would be null only when the input argument url is null . To express that contract, you would annotate this
method as shown in the following code:
[return: NotNullIfNotNull("url")]
string? GetTopLevelDomainFromFullUrl(string? url);
The return value and the argument have both been annotated with the ? indicating that either could be null .
The attribute further clarifies that the return value won't be null when the url argument isn't null .
You specify conditional postconditions using these attributes:
MaybeNullWhen: A non-nullable input argument may be null when the method returns the specified bool
value.
NotNullWhen: A nullable input argument will not be null when the method returns the specified bool value.
NotNullIfNotNull: A return value isn't null if the input argument for the specified parameter isn't null.
[DoesNotReturn]
private void FailFast()
{
throw new InvalidOperationException();
}
// unreachable code:
this.field = containedField;
}
In the second case, you add the DoesNotReturnIf attribute to a Boolean parameter of the method. You can modify
the previous example as follows:
See also
C# Reference
C# Programming Guide
#if (C# reference)
9/3/2020 • 2 minutes to read • Edit Online
When the C# compiler encounters an #if directive, followed eventually by an #endif directive, it compiles the
code between the directives only if the specified symbol is defined. Unlike C and C++, you cannot assign a
numeric value to a symbol. The #if statement in C# is Boolean and only tests whether the symbol has been
defined or not. For example:
#if DEBUG
Console.WriteLine("Debug version");
#endif
You can use the operators == (equality) and != (inequality) only to test for the bool values true or false . true
means the symbol is defined. The statement #if DEBUG has the same meaning as #if (DEBUG == true) . You can
use the && (and), || (or), and ! (not) operators to evaluate whether multiple symbols have been defined. You can
also group symbols and operators with parentheses.
Remarks
#if , along with the #else, #elif, #endif, #define, and #undef directives, lets you include or exclude code based on
the existence of one or more symbols. This can be useful when compiling code for a debug build or when
compiling for a specific configuration.
A conditional directive beginning with a #if directive must explicitly be terminated with a #endif directive.
#define lets you define a symbol. By then using the symbol as the expression passed to the #if directive, the
expression evaluates to true .
You can also define a symbol with the -define compiler option. You can undefine a symbol with #undef.
A symbol that you define with -define or with #define doesn't conflict with a variable of the same name. That
is, a variable name should not be passed to a preprocessor directive, and a symbol can only be evaluated by a
preprocessor directive.
The scope of a symbol created with #define is the file in which it was defined.
The build system is also aware of predefined preprocessor symbols representing different target frameworks in
SDK-style projects. They're useful when creating applications that can target more than one .NET implementation
or version.
TA RGET F RA M EW O RK S SY M B O L S
NOTE
For traditional .NET Framework projects, you have to manually configure the conditional compilation symbols for the
different target frameworks in Visual Studio via the project's properties pages.
Other predefined symbols include the DEBUG and TRACE constants. You can override the values set for the
project using #define . The DEBUG symbol, for example, is automatically set depending on your build
configuration properties ("Debug" or "Release" mode).
Examples
The following example shows you how to define a MYTEST symbol on a file and then test the values of the
MYTEST and DEBUG symbols. The output of this example depends on whether you built the project on Debug or
Release configuration mode.
#define MYTEST
using System;
public class MyClass
{
static void Main()
{
#if (DEBUG && !MYTEST)
Console.WriteLine("DEBUG is defined");
#elif (!DEBUG && MYTEST)
Console.WriteLine("MYTEST is defined");
#elif (DEBUG && MYTEST)
Console.WriteLine("DEBUG and MYTEST are defined");
#else
Console.WriteLine("DEBUG and MYTEST are not defined");
#endif
}
}
The following example shows you how to test for different target frameworks so you can use newer APIs when
possible:
See also
C# Reference
C# Programming Guide
C# Preprocessor Directives
How to: Compile Conditionally with Trace and Debug
#else (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
#else lets you create a compound conditional directive, so that, if none of the expressions in the preceding #if or
(optional) #elif directives evaluate to true , the compiler will evaluate all code between #else and the subsequent
#endif .
Remarks
#endif must be the next preprocessor directive after #else . See #if for an example of how to use #else .
See also
C# Reference
C# Programming Guide
C# Preprocessor Directives
#elif (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
#elif lets you create a compound conditional directive. The #elif expression will be evaluated if neither the
preceding #if nor any preceding, optional, #elif directive expressions evaluate to true . If a #elif expression
evaluates to true , the compiler evaluates all the code between the #elif and the next conditional directive. For
example:
#define VC7
//...
#if debug
Console.WriteLine("Debug build");
#elif VC7
Console.WriteLine("Visual Studio 7");
#endif
You can use the operators == (equality), != (inequality), && (and), and || (or), to evaluate multiple symbols.
You can also group symbols and operators with parentheses.
Remarks
#elif is equivalent to using:
#else
#if
Using #elif is simpler, because each #if requires a #endif, whereas a #elif can be used without a matching
#endif .
See #if for an example of how to use #elif .
See also
C# Reference
C# Programming Guide
C# Preprocessor Directives
#endif (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
#endif specifies the end of a conditional directive, which began with the #if directive. For example,
#define DEBUG
// ...
#if DEBUG
Console.WriteLine("Debug version");
#endif
Remarks
A conditional directive, beginning with a #if directive, must explicitly be terminated with a #endif directive. See
#if for an example of how to use #endif .
See also
C# Reference
C# Programming Guide
C# Preprocessor Directives
#define (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
You use #define to define a symbol. When you use the symbol as the expression that's passed to the #if directive,
the expression will evaluate to true , as the following example shows:
#define DEBUG
Remarks
NOTE
The #define directive cannot be used to declare constant values as is typically done in C and C++. Constants in C# are
best defined as static members of a class or struct. If you have several such constants, consider creating a separate
"Constants" class to hold them.
Symbols can be used to specify conditions for compilation. You can test for the symbol with either #if or #elif. You
can also use the ConditionalAttribute to perform conditional compilation.
You can define a symbol, but you cannot assign a value to a symbol. The #define directive must appear in the file
before you use any instructions that aren't also preprocessor directives.
You can also define a symbol with the -define compiler option. You can undefine a symbol with #undef.
A symbol that you define with -define or with #define does not conflict with a variable of the same name. That
is, a variable name should not be passed to a preprocessor directive and a symbol can only be evaluated by a
preprocessor directive.
The scope of a symbol that was created by using #define is the file in which the symbol was defined.
As the following example shows, you must put #define directives at the top of the file.
#define DEBUG
//#define TRACE
#undef TRACE
using System;
#if (TRACE)
Console.WriteLine("Tracing is enabled.");
#endif
}
}
// Output:
// Debugging is enabled.
For an example of how to undefine a symbol, see #undef.
See also
C# Reference
C# Programming Guide
C# Preprocessor Directives
const
How to: Compile Conditionally with Trace and Debug
#undef
#if
#undef (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
#undef lets you undefine a symbol, such that, by using the symbol as the expression in a #if directive, the
expression will evaluate to false .
A symbol can be defined either with the #define directive or the -define compiler option. The #undef directive
must appear in the file before you use any statements that are not also directives.
Example
// preprocessor_undef.cs
// compile with: /d:DEBUG
#undef DEBUG
using System;
class MyClass
{
static void Main()
{
#if DEBUG
Console.WriteLine("DEBUG is defined");
#else
Console.WriteLine("DEBUG is not defined");
#endif
}
}
See also
C# Reference
C# Programming Guide
C# Preprocessor Directives
#warning (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
#warning lets you generate a CS1030 level one compiler warning from a specific location in your code. For
example:
Remarks
A common use of #warning is in a conditional directive. It is also possible to generate a user-defined error with
#error.
Example
// preprocessor_warning.cs
// CS1030 expected
#define DEBUG
class MainClass
{
static void Main()
{
#if DEBUG
#warning DEBUG is defined
#endif
}
}
See also
C# Reference
C# Programming Guide
C# Preprocessor Directives
#error (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
#error lets you generate a CS1029 user-defined error from a specific location in your code. For example:
NOTE
The compiler treats #error version in a special way and reports a compiler error, CS8304, with a message containing the
used compiler and language versions.
Remarks
A common use of #error is in a conditional directive.
It is also possible to generate a user-defined warning with #warning.
Example
// preprocessor_error.cs
// CS1029 expected
#define DEBUG
class MainClass
{
static void Main()
{
#if DEBUG
#error DEBUG is defined
#endif
}
}
See also
C# Reference
C# Programming Guide
C# Preprocessor Directives
#line (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
#line lets you modify the compiler's line numbering and (optionally) the file name output for errors and
warnings.
The following example shows how to report two warnings associated with line numbers. The #line 200 directive
forces the next line's number to be 200 (although the default is #6), and until the next #line directive, the filename
will be reported as "Special". The #line default directive returns the line numbering to its default numbering,
which counts the lines that were renumbered by the previous directive.
class MainClass
{
static void Main()
{
#line 200 "Special"
int i;
int j;
#line default
char c;
float f;
#line hidden // numbering not affected
string s;
double d;
}
}
Special(200,13): warning CS0168: The variable 'i' is declared but never used
Special(201,13): warning CS0168: The variable 'j' is declared but never used
MainClass.cs(9,14): warning CS0168: The variable 'c' is declared but never used
MainClass.cs(10,15): warning CS0168: The variable 'f' is declared but never used
MainClass.cs(12,16): warning CS0168: The variable 's' is declared but never used
MainClass.cs(13,16): warning CS0168: The variable 'd' is declared but never used
Remarks
The #line directive might be used in an automated, intermediate step in the build process. For example, if lines
were removed from the original source code file, but you still wanted the compiler to generate output based on the
original line numbering in the file, you could remove lines and then simulate the original line numbering with
#line .
The #line hidden directive hides the successive lines from the debugger, such that when the developer steps
through the code, any lines between a #line hidden and the next #line directive (assuming that it is not another
#line hidden directive) will be stepped over. This option can also be used to allow ASP.NET to differentiate between
user-defined and machine-generated code. Although ASP.NET is the primary consumer of this feature, it is likely
that more source generators will make use of it.
A #line hidden directive does not affect file names or line numbers in error reporting. That is, if an error is
encountered in a hidden block, the compiler will report the current file name and line number of the error.
The #line filename directive specifies the file name you want to appear in the compiler output. By default, the
actual name of the source code file is used. The file name must be in double quotation marks ("") and must be
preceded by a line number.
A source code file can have any number of #line directives.
Example 1
The following example shows how the debugger ignores the hidden lines in the code. When you run the example, it
will display three lines of text. However, when you set a break point, as shown in the example, and hit F10 to step
through the code, you will notice that the debugger ignores the hidden line. Notice also that even if you set a break
point at the hidden line, the debugger will still ignore it.
// preprocessor_linehidden.cs
using System;
class MainClass
{
static void Main()
{
Console.WriteLine("Normal line #1."); // Set break point here.
#line hidden
Console.WriteLine("Hidden line.");
#line default
Console.WriteLine("Normal line #2.");
}
}
See also
C# Reference
C# Programming Guide
C# Preprocessor Directives
#region (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
#region lets you specify a block of code that you can expand or collapse when using the outlining feature of the
code editor. In longer code files, it is convenient to be able to collapse or hide one or more regions so that you can
focus on the part of the file that you are currently working on. The following example shows how to define a
region:
Remarks
A #region block must be terminated with a #endregion directive.
A #region block cannot overlap with a #if block. However, a #region block can be nested in a #if block, and a
#if block can be nested in a #region block.
See also
C# Reference
C# Programming Guide
C# Preprocessor Directives
#endregion (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
See also
C# Reference
C# Programming Guide
C# Preprocessor Directives
#pragma (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
#pragma gives the compiler special instructions for the compilation of the file in which it appears. The instructions
must be supported by the compiler. In other words, you cannot use #pragma to create custom preprocessing
instructions. The Microsoft C# compiler supports the following two #pragma instructions:
#pragma warning
#pragma checksum
Syntax
#pragma pragma-name pragma-arguments
Parameters
pragma-name
The name of a recognized pragma.
pragma-arguments
Pragma-specific arguments.
See also
C# Reference
C# Programming Guide
C# Preprocessor Directives
#pragma warning
#pragma checksum
#pragma warning (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
#pragma warning disable warning-list
#pragma warning restore warning-list
Parameters
warning-list
A comma-separated list of warning numbers. The "CS" prefix is optional.
When no warning numbers are specified, disable disables all warnings and restore enables all warnings.
NOTE
To find warning numbers in Visual Studio, build your project and then look for the warning numbers in the Output window.
Example
// pragma_warning.cs
using System;
See also
C# Reference
C# Programming Guide
C# Preprocessor Directives
C# Compiler Errors
#pragma checksum (C# Reference)
9/3/2020 • 2 minutes to read • Edit Online
Generates checksums for source files to aid with debugging ASP.NET pages.
Syntax
#pragma checksum "filename" "{guid}" "checksum bytes"
Parameters
"filename"
The name of the file that requires monitoring for changes or updates.
"{guid}"
The Globally Unique Identifier (GUID) for the hash algorithm.
"checksum_bytes"
The string of hexadecimal digits representing the bytes of the checksum. Must be an even number of hexadecimal
digits. An odd number of digits results in a compile-time warning, and the directive are ignored.
Remarks
The Visual Studio debugger uses a checksum to make sure that it always finds the right source. The compiler
computes the checksum for a source file, and then emits the output to the program database (PDB) file. The
debugger then uses the PDB to compare against the checksum that it computes for the source file.
This solution does not work for ASP.NET projects, because the computed checksum is for the generated source file,
rather than the .aspx file. To address this problem, #pragma checksum provides checksum support for ASP.NET
pages.
When you create an ASP.NET project in Visual C#, the generated source file contains a checksum for the .aspx file,
from which the source is generated. The compiler then writes this information into the PDB file.
If the compiler encounters no #pragma checksum directive in the file, it computes the checksum and writes the
value to the PDB file.
Example
class TestClass
{
static int Main()
{
#pragma checksum "file.cs" "{406EA660-64CF-4C82-B6F0-42D48172A799}" "ab007f1d23d9" // New checksum
}
}
See also
C# Reference
C# Programming Guide
C# Preprocessor Directives
C# Compiler Options
9/3/2020 • 2 minutes to read • Edit Online
The compiler produces executable (.exe) files, dynamic-link libraries (.dll), or code modules (.netmodule).
Every compiler option is available in two forms: -option and /option . The documentation only shows the
-option form.
In Visual Studio, you set compiler options in the web.config file. For more information, see <compiler>
Element.
In this section
Command-line Building With csc.exe Information about building a Visual C# application from the
command line.
How to set environment variables for the Visual Studio Command Line Provides steps for running
VsDevCmd.bat to enable command-line builds.
C# Compiler Options Listed by Category A categorical listing of the compiler options.
C# Compiler Options Listed Alphabetically An alphabetical listing of the compiler options.
Related sections
Build Page, Project Designer Setting properties that govern how your project is compiled, built, and
debugged. Includes information about custom build steps in Visual C# projects.
Default and Custom Builds Information on build types and configurations.
Preparing and Managing Builds Procedures for building within the Visual Studio development
environment.
Command-line build with csc.exe
9/3/2020 • 3 minutes to read • Edit Online
You can invoke the C# compiler by typing the name of its executable file (csc.exe) at a command prompt.
If you use the Developer Command Prompt for Visual Studio window, all the necessary environment
variables are set for you. For information on how to access this tool, see the Developer Command Prompt for
Visual Studio topic.
If you use a standard Command Prompt window, you must adjust your path before you can invoke csc.exe from
any subdirectory on your computer. You also must run VsDevCmd.bat to set the appropriate environment
variables to support command-line builds. For more information about VsDevCmd.bat, including instructions for
how to find and run it, see How to set environment variables for the Visual Studio Command Line.
If you're working on a computer that has only the Windows Software Development Kit (SDK), you can use the C#
compiler at the SDK Command Prompt , which you open from the Microsoft .NET Framework SDK menu
option.
You can also use MSBuild to build C# programs programmatically. For more information, see MSBuild.
The csc.exe executable file usually is located in the Microsoft.NET\Framework\<Version> folder under the
Windows directory. Its location might vary depending on the exact configuration of a particular computer. If more
than one version of the .NET Framework is installed on your computer, you'll find multiple versions of this file. For
more information about such installations, see How to: determine which versions of the .NET Framework are
installed.
TIP
When you build a project by using the Visual Studio IDE, you can display the csc command and its associated compiler
options in the Output window. To display this information, follow the instructions in How to: View, Save, and Configure
Build Log Files to change the verbosity level of the log data to Normal or Detailed . After you rebuild your project, search
the Output window for csc to find the invocation of the C# compiler.
In this topic
Rules for command-line syntax
Sample command lines
Differences between C# compiler and C++ compiler output
csc File.cs
Compiles all the C# files in the current directory with optimizations enabled and defines the DEBUG symbol.
The output is File2.exe:
Compiles all the C# files in the current directory producing a debug version of File2.dll. No logo and no
warnings are displayed:
See also
C# Compiler Options
C# Compiler Options Listed Alphabetically
C# Compiler Options Listed by Category
Main() and Command-Line Arguments
Command-Line Arguments
How to display command-line arguments
Main() Return Values
How to set environment variables for the Visual
Studio Command Line
9/3/2020 • 2 minutes to read • Edit Online
The VsDevCmd.bat file sets the appropriate environment variables to enable command-line builds.
NOTE
Visual Studio 2015 and earlier versions used VSVARS32.bat, not VsDevCmd.bat for the same purpose. This file was stored in
\Program Files\Microsoft Visual Studio\Version\Common7\Tools or Program Files (x86)\Microsoft Visual
Studio\Version\Common7\Tools.
If the current version of Visual Studio is installed on a computer that also has an earlier version of Visual Studio,
you should not run VsDevCmd.bat and VSVARS32.BAT from different versions in the same Command Prompt
window. Instead, you should run the command for each version in its own window.
To run VsDevCmd.BAT
1. From the Star t menu, open the Developer Command Prompt for VS 2019 . It's in the Visual Studio
2019 folder.
2. Change to the \Program Files\Microsoft Visual Studio\Version\Offering\Common7\Tools or \Program Files
(x86)\Microsoft Visual Studio\Version\Offering\Common7\Tools subdirectory of your installation. (Version
is 2019 for the current version. Offering is one of Enterprise, Professional or Community.)
3. Run VsDevCmd.bat by typing VsDevCmd .
Cau t i on
VsDevCmd.bat can vary from computer to computer. Do not replace a missing or damaged VsDevCmd.bat
file with a VsDevCmd.bat from another computer. Instead, rerun setup to replace the missing file.
Available options for VsDevCmd.BAT
To see the available options for VsDevCmd.BAT, run the command with the -help option:
VsDevCmd.bat -help
See also
Command-line Building With csc.exe
C# Compiler Options Listed by Category
9/3/2020 • 3 minutes to read • Edit Online
The following compiler options are sorted by category. For an alphabetical list, see C# Compiler Options Listed
Alphabetically.
Optimization
O P T IO N P URP O SE
Output Files
O P T IO N P URP O SE
-pdb Specifies the file name and location of the .pdb file.
-target Specifies the format of the output file using one of the
following options: -target:appcontainerexe, -target:exe, -
target:library, -target:module, -target:winexe, or -
target:winmdobj.
-delaysign Instructs the compiler to add the public key but to leave the
assembly unsigned.
-publicsign Apply a public key without signing the assembly, but set the
bit in the assembly indicating the assembly is signed.
-analyzer Run the analyzers from this assembly (Short form: /a)
Debugging/Error Checking
O P T IO N P URP O SE
Preprocessor
O P T IO N P URP O SE
Resources
O P T IO N P URP O SE
Miscellaneous
O P T IO N P URP O SE
-codepage Specifies the code page to use for all source code files in the
compilation.
-checksumalgorithm:<alg> Specify the algorithm for calculating the source file checksum
stored in PDB. Supported values are: SHA256 (default) or
SHA1.
Due to collision problems with SHA1, Microsoft recommends
SHA256.
Obsolete Options
O P T IO N P URP O SE
See also
C# Compiler Options
C# Compiler Options Listed Alphabetically
How to set environment variables for the Visual Studio Command Line
C# Compiler Options Listed Alphabetically
9/3/2020 • 3 minutes to read • Edit Online
The following compiler options are sorted alphabetically. For a categorical list, see C# Compiler Options Listed by
Category.
O P T IO N P URP O SE
-analyzer Run the analyzers from this assembly (Short form: -a)
-bugreport Creates a 'Bug Report' file. This file will be sent together with
any crash information if it is used with -errorreport:prompt or
-errorreport:send.
-delaysign Delay-signs the assembly by using only the public part of the
strong name key.
-errorendlocation Output line and column of the end location of each error.
-main Specifies the type that contains the entry point (ignore all
other possible entry points).
-out Specifies the output file name (default: base name of file with
main class or first file).
-pdb Specifies the file name and location of the .pdb file.
-platform Limits which platforms this code can run on: x86, Itanium,
x64, anycpu, or anycpu32bitpreferred. The default is anycpu.
-publicsign Apply a public key without signing the assembly, but set the
bit in the assembly indicating the assembly is signed.
-target Specifies the format of the output file by using one of the
following options: -target:appcontainerexe, -target:exe, -
target:library, -target:module, -target:winexe, -
target:winmdobj.
See also
C# Compiler Options
C# Compiler Options Listed by Category
How to set environment variables for the Visual Studio Command Line
<compiler> Element
@ (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The @ option lets you specify a file that contains compiler options and source code files to compile.
Syntax
@response_file
Arguments
response_file
A file that lists compiler options or source code files to compile.
Remarks
The compiler options and source code files will be processed by the compiler just as if they had been specified on
the command line.
To specify more than one response file in a compilation, specify multiple response file options. For example:
@file1.rsp @file2.rsp
In a response file, multiple compiler options and source code files can appear on one line. A single compiler option
specification must appear on one line (cannot span multiple lines). Response files can have comments that begin
with the # symbol.
Specifying compiler options from within a response file is just like issuing those commands on the command line.
See Building from the Command Line for more information.
The compiler processes the command options as they are encountered. Therefore, command line arguments can
override previously listed options in response files. Conversely, options in a response file will override options
listed previously on the command line or in other response files.
C# provides the csc.rsp file, which is located in the same directory as the csc.exe file. See -noconfig for more
information on csc.rsp.
This compiler option cannot be set in the Visual Studio development environment, nor can it be changed
programmatically.
Example
The following are a few lines from a sample response file:
See also
C# Compiler Options
-addmodule (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
This option adds a module that was created with the target:module switch to the current compilation.
Syntax
-addmodule:file[;file2]
Arguments
file , file2
An output file that contains metadata. The file cannot contain an assembly manifest. To import more than one file,
separate file names with either a comma or a semicolon.
Remarks
All modules added with -addmodule must be in the same directory as the output file at run time. That is, you can
specify a module in any directory at compile time but the module must be in the application directory at run time.
If the module is not in the application directory at run time, you will get a TypeLoadException.
file cannot contain an assembly. For example, if the output file was created with -target:module, its metadata
can be imported with -addmodule .
If the output file was created with a -target option other than -target:module , its metadata cannot be imported
with -addmodule but can be imported with -reference.
This compiler option is unavailable in Visual Studio; a project cannot reference a module. In addition, this compiler
option cannot be changed programmatically.
Example
Compile source file input.cs and add metadata from metad1.netmodule and metad2.netmodule to produce
out.exe :
See also
C# Compiler Options
Managing Project and Solution Properties
Multifile Assemblies
How to: Build a Multifile Assembly
-appconfig (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -appconfig compiler option enables a C# application to specify the location of an assembly's application
configuration (app.config) file to the common language runtime (CLR) at assembly binding time.
Syntax
-appconfig:file
Arguments
file
Required. The application configuration file that contains assembly binding settings.
Remarks
One use of -appconfig is advanced scenarios in which an assembly has to reference both the .NET Framework
version and the .NET Framework for Silverlight version of a particular reference assembly at the same time. For
example, a XAML designer written in Windows Presentation Foundation (WPF) might have to reference both the
WPF Desktop, for the designer's user interface, and the subset of WPF that is included with Silverlight. The same
designer assembly has to access both assemblies. By default, the separate references cause a compiler error,
because assembly binding sees the two assemblies as equivalent.
The -appconfig compiler option enables you to specify the location of an app.config file that disables the default
behavior by using a <supportPortability> tag, as shown in the following example.
<supportPortability PKT="7cec85d7bea7798e" enable="false"/>
The compiler passes the location of the file to the CLR's assembly-binding logic.
NOTE
If you are using the Microsoft Build Engine (MSBuild) to build your application, you can set the -appconfig compiler option
by adding a property tag to the .csproj file. To use the app.config file that is already set in the project, add property tag
<UseAppConfigForCompiler> to the .csproj file and set its value to true . To specify a different app.config file, add property
tag <AppConfigForCompiler> and set its value to the location of the file.
Example
The following example shows an app.config file that enables an application to have references to both the .NET
Framework implementation and the .NET Framework for Silverlight implementation of any .NET Framework
assembly that exists in both implementations. The -appconfig compiler option specifies the location of this
app.config file.
<configuration>
<runtime>
<assemblyBinding>
<supportPortability PKT="7cec85d7bea7798e" enable="false"/>
<supportPortability PKT="31bf3856ad364e35" enable="false"/>
</assemblyBinding>
</runtime>
</configuration>
See also
<supportPortability> Element
C# Compiler Options Listed Alphabetically
-baseaddress (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -baseaddress option lets you specify the preferred base address at which to load a DLL. For more
information about when and why to use this option, see Larry Osterman's WebLog.
Syntax
-baseaddress:address
Arguments
address
The base address for the DLL. This address can be specified as a decimal, hexadecimal, or octal number.
Remarks
The default base address for a DLL is set by the .NET Framework common language runtime.
Be aware that the lower-order word in this address will be rounded. For example, if you specify 0x11110001, it will
be rounded to 0x11110000.
To complete the signing process for a DLL, use SN.EXE with the -R option.
To set this compiler option in the Visual Studio development environment
1. Open the project's Proper ties page.
2. Click the Build property page.
3. Click the Advanced button.
4. Modify the DLL Base Address property.
To set this compiler option programmatically, see BaseAddress.
See also
ProcessModule.BaseAddress
C# Compiler Options
Managing Project and Solution Properties
-bugreport (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
Specifies that debug information should be placed in a file for later analysis.
Syntax
-bugreport:file
Arguments
file
The name of the file that you want to contain your bug report.
Remarks
The -bugrepor t option specifies that the following information should be placed in file :
A copy of all source code files in the compilation.
A listing of the compiler options used in the compilation.
Version information about your compiler, run time, and operating system.
Referenced assemblies and modules, saved as hexadecimal digits, except assemblies that ship with the .NET
Framework and SDK.
Compiler output, if any.
A description of the problem, which you will be prompted for.
A description of how you think the problem should be fixed, which you will be prompted for.
If this option is used with -errorrepor t:prompt or -errorrepor t:send , the information in the file will be sent to
Microsoft Corporation.
Because a copy of all source code files will be placed in file , you might want to reproduce the suspected code
defect in the shortest possible program.
This compiler option is unavailable in Visual Studio and cannot be changed programmatically.
Notice that contents of the generated file expose source code that could result in inadvertent information
disclosure.
See also
C# Compiler Options
-errorreport (C# Compiler Options)
Managing Project and Solution Properties
-checked (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -checked option specifies whether an integer arithmetic statement that results in a value that is outside the
range of the data type, and that is not in the scope of a checked or unchecked keyword, causes a run-time
exception.
Syntax
-checked[+ | -]
Remarks
An integer arithmetic statement that is in the scope of a checked or unchecked keyword is not subject to the effect
of the -checked option.
If an integer arithmetic statement that is not in the scope of a checked or unchecked keyword results in a value
outside the range of the data type, and -checked+ (or -checked ) is used in the compilation, that statement
causes an exception at run time. If -checked- is used in the compilation, that statement does not cause an
exception at run time.
The default value for this option is -checked- ; overflow checking is disabled.
Sometimes, automated tools that are used to build large applications set -checked to +. One scenario for using -
checked- is to override the tool's global default by specifying -checked-.
To set this compiler option in the Visual Studio development environment
1. Open the project's Proper ties page. For more information, see Build Page, Project Designer (C#).
2. Click the Build property page.
3. Click the Advanced button.
4. Modify the Check for arithmetic overflow property.
To access this compiler option programmatically, see CheckForOverflowUnderflow.
Example
The following command compiles t2.cs . The use of -checked in the command specifies that any integer
arithmetic statement in the file that is not in the scope of a checked or unchecked keyword, and that results in a
value that is outside the range of the data type, causes an exception at run time.
See also
C# Compiler Options
Managing Project and Solution Properties
-codepage (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
This option specifies which codepage to use during compilation if the required page is not the current default
codepage for the system.
Syntax
-codepage:id
Arguments
id
The id of the code page to use for all source code files in the compilation.
Remarks
The compiler will first attempt to interpret all source files as UTF-8. If your source code files are in an encoding
other than UTF-8 and use characters other than 7-bit ASCII characters, use the -codepage option to specify which
code page should be used. -codepage applies to all source code files in your compilation.
See GetCPInfo for information on how to find which code pages are supported on your system.
This compiler option is unavailable in Visual Studio and cannot be changed programmatically.
See also
C# Compiler Options
Managing Project and Solution Properties
-debug (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -debug option causes the compiler to generate debugging information and place it in the output file or files.
Syntax
-debug[+ | -]
-debug:{full | pdbonly}
Arguments
+ | -
Specifying + , or just -debug , causes the compiler to generate debugging information and place it in a program
database (.pdb file). Specifying - , which is in effect if you do not specify -debug , causes no debug information to
be created.
full | pdbonly
Specifies the type of debugging information generated by the compiler. The full argument, which is in effect if you
do not specify -debug:pdbonly , enables attaching a debugger to the running program. Specifying pdbonly
allows source code debugging when the program is started in the debugger but will only display assembler when
the running program is attached to the debugger.
Remarks
Use this option to create debug builds. If -debug , -debug+ , or -debug:full is not specified, you will not be able
to debug the output file of your program.
If you use -debug:full , be aware that there is some impact on the speed and size of JIT optimized code and a
small impact on code quality with -debug:full . We recommend -debug:pdbonly or no PDB for generating
release code.
NOTE
One difference between -debug:pdbonly and -debug:full is that with -debug:full the compiler emits a
DebuggableAttribute, which is used to tell the JIT compiler that debug information is available. Therefore, you will get an
error if your code contains the DebuggableAttribute set to false if you use -debug:full.
For more information on how to configure the debug performance of an application, see Making an Image Easier
to Debug.
To change the location of the .pdb file, see -pdb (C# Compiler Options).
To set this compiler option in the Visual Studio development environment
1. Open the project's Proper ties page.
2. Click the Build property page.
3. Click the Advanced button.
4. Modify the Debug Info property.
For information on how to set this compiler option programmatically, see DebugSymbols.
Example
Place debugging information in output file app.pdb :
See also
C# Compiler Options
Managing Project and Solution Properties
-define (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -define option defines name as a symbol in all source code files your program.
Syntax
-define:name[;name2]
Arguments
name , name2
The name of one or more symbols that you want to define.
Remarks
The -define option has the same effect as using a #define preprocessor directive except that the compiler option
is in effect for all files in the project. A symbol remains defined in a source file until an #undef directive in the
source file removes the definition. When you use the -define option, an #undef directive in one file has no effect
on other source code files in the project.
You can use symbols created by this option with #if, #else, #elif, and #endif to compile source files conditionally.
-d is the short form of -define .
You can define multiple symbols with -define by using a semicolon or comma to separate symbol names. For
example:
-define:DEBUG;TUESDAY
The C# compiler itself defines no symbols or macros that you can use in your source code; all symbol definitions
must be user-defined.
NOTE
The C# #define does not allow a symbol to be given a value, as in languages such as C++. For example, #define cannot
be used to create a macro or to define a constant. If you need to define a constant, use an enum variable. If you want to
create a C++ style macro, consider alternatives such as generics. Since macros are notoriously error-prone, C# disallows
their use but provides safer alternatives.
Example
// preprocessor_define.cs
// compile with: -define:xx
// or uncomment the next line
// #define xx
using System;
public class Test
{
public static void Main()
{
#if (xx)
Console.WriteLine("xx defined");
#else
Console.WriteLine("xx not defined");
#endif
}
}
See also
C# Compiler Options
Managing Project and Solution Properties
-delaysign (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
This option causes the compiler to reserve space in the output file so that a digital signature can be added later.
Syntax
-delaysign[ + | - ]
Arguments
+ | -
Use -delaysign- if you want a fully signed assembly. Use -delaysign+ if you only want to place the public key in
the assembly. The default is -delaysign- .
Remarks
The -delaysign option has no effect unless used with -keyfile or -keycontainer.
The -delaysign and -publicsign options are mutually exclusive.
When you request a fully signed assembly, the compiler hashes the file that contains the manifest (assembly
metadata) and signs that hash with the private key. That operation creates a digital signature which is stored in the
file that contains the manifest. When an assembly is delay signed, the compiler does not compute and store the
signature, but reserves space in the file so the signature can be added later.
For example, using -delaysign+ allows a tester to put the assembly in the global cache. After testing, you can fully
sign the assembly by placing the private key in the assembly using the Assembly Linker utility.
For more information, see Creating and Using Strong-Named Assemblies and Delay Signing an Assembly.
To set this compiler option in the Visual Studio development environment
1. Open the Proper ties page for the project.
2. Modify the Delay sign only property.
For information on how to set this compiler option programmatically, see DelaySign.
See also
C# -publicsign option
C# Compiler Options
Managing Project and Solution Properties
-deterministic
9/3/2020 • 2 minutes to read • Edit Online
Causes the compiler to produce an assembly whose byte-for-byte output is identical across compilations for
identical inputs.
Syntax
-deterministic
Remarks
By default, compiler output from a given set of inputs is unique, since the compiler adds a timestamp and a GUID
that is generated from random numbers. You use the -deterministic option to produce a deterministic assembly,
one whose binary content is identical across compilations as long as the input remains the same.
The compiler considers the following inputs for the purpose of determinism:
The sequence of command-line parameters.
The contents of the compiler's .rsp response file.
The precise version of the compiler used, and its referenced assemblies.
The current directory path.
The binary contents of all files explicitly passed to the compiler either directly or indirectly, including:
Source files
Referenced assemblies
Referenced modules
Resources
The strong name key file
@ response files
Analyzers
Rulesets
Additional files that may be used by analyzers
The current culture (for the language in which diagnostics and exception messages are produced).
The default encoding (or the current code page) if the encoding is not specified.
The existence, non-existence, and contents of files on the compiler's search paths (specified, for example, by
-lib or -recurse ).
The CLR platform on which the compiler is run.
The value of %LIBPATH% , which can affect analyzer dependency loading.
When sources are publicly available, deterministic compilation can be used for establishing whether a binary is
compiled from a trusted source. It can also be useful in a continuous build system for determining whether build
steps that are dependent on changes to a binary need to be executed.
See also
C# Compiler Options
Managing Project and Solution Properties
-doc (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -doc option allows you to place documentation comments in an XML file.
Syntax
-doc:file
Arguments
file
The output file for XML, which is populated with the comments in the source code files of the compilation.
Remarks
In source code files, documentation comments that precede the following can be processed and added to
the XML file:
Such user-defined types as a class, delegate, or interface
Such members as a field, event, property, or method
The source code file that contains Main is output first into the XML.
To use the generated .xml file for use with the IntelliSense feature, let the file name of the .xml file be the
same as the assembly you want to support and then make sure the .xml file is in the same directory as the
assembly. Thus, when the assembly is referenced in the Visual Studio project, the .xml file is found as well.
See Supplying Code Comments and for more information.
Unless you compile with -target:module, file will contain <assembly></assembly> tags specifying the
name of the file containing the assembly manifest for the output file of the compilation.
NOTE
The -doc option applies to all input files; or, if set in the Project Settings, all files in the project. To disable warnings
related to documentation comments for a specific file or section of code, use #pragma warning.
See Recommended Tags for Documentation Comments for ways to generate documentation from
comments in your code.
To set this compiler option in the Visual Studio development environment
1. Open the project's Proper ties page.
2. Click the Build tab.
3. Modify the XML documentation file property.
For information on how to set this compiler option programmatically, see DocumentationFile.
See also
C# Compiler Options
Managing Project and Solution Properties
-errorreport (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
This option provides a convenient way to report a C# internal compiler error to Microsoft.
NOTE
On Windows Vista and Windows Server 2008, the error reporting settings that you make for Visual Studio do not override
the settings made through Windows Error Reporting (WER). WER settings always take precedence over Visual Studio error
reporting settings.
Syntax
-errorreport:{ none | prompt | queue | send }
Arguments
none
Reports about internal compiler errors will not be collected or sent to Microsoft.
prompt Prompts you to send a report when you receive an internal compiler error. prompt is the default when
you compile an application in the development environment.
queue Queues the error report. When you log on with administrative credentials, you can report any failures
since the last time that you were logged on. You will not be prompted to send reports for failures more than once
every three days. queue is the default when you compile an application at the command line.
send Automatically sends reports of internal compiler errors to Microsoft. To enable this option, you must first
agree to the Microsoft data collection policy. The first time that you specify -errorrepor t:send on a computer, a
compiler message will refer you to a Web site that contains the Microsoft data collection policy.
Remarks
An internal compiler error (ICE) results when the compiler cannot process a source code file. When an ICE occurs,
the compiler does not produce an output file or any useful diagnostic that you can use to fix your code.
In previous releases, when you received an ICE, you were encouraged to contact Microsoft Product Support
Services to report the problem. By using -errorrepor t , you can provide ICE information to the Visual C# team.
Your error reports can help improve future compiler releases.
A user's ability to send reports depends on computer and user policy permissions.
To set this compiler option in the Visual Studio development environment
1. Open the project's Proper ties page. For more information, see Build Page, Project Designer (C#).
2. Click the Build property page.
3. Click the Advanced button.
4. Modify the Internal Compiler Error Repor ting property.
For information about how to set this compiler option programmatically, see ErrorReport.
See also
C# Compiler Options
-filealign (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -filealign option lets you specify the size of sections in your output file.
Syntax
-filealign:number
Arguments
number
A value that specifies the size of sections in the output file. Valid values are 512, 1024, 2048, 4096, and 8192. These
values are in bytes.
Remarks
Each section will be aligned on a boundary that is a multiple of the -filealign value. There is no fixed default. If -
filealign is not specified, the common language runtime picks a default at compile time.
By specifying the section size, you affect the size of the output file. Modifying section size may be useful for
programs that will run on smaller devices.
Use DUMPBIN to see information about sections in your output file.
To set this compiler option in the Visual Studio development environment
1. Open the project's Proper ties page.
2. Click the Build property page.
3. Click the Advanced button.
4. Modify the File Alignment property.
For information on how to set this compiler option programmatically, see FileAlignment.
See also
C# Compiler Options
Managing Project and Solution Properties
-fullpaths (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -fullpaths option causes the compiler to specify the full path to the file when listing compilation errors and
warnings.
Syntax
-fullpaths
Remarks
By default, errors and warnings that result from compilation specify the name of the file in which an error was
found. The -fullpaths option causes the compiler to specify the full path to the file.
This compiler option is unavailable in Visual Studio and cannot be changed programmatically.
See also
C# Compiler Options
-help, -? (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
This option sends a listing of compiler options, and a brief description of each option, to stdout.
Syntax
-help
-?
Remarks
If this option is included in a compilation, no output file will be created and no compilation will take place.
This compiler option is unavailable in Visual Studio and cannot be changed programmatically.
See also
C# Compiler Options
Managing Project and Solution Properties
-highentropyva (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -highentropyva compiler option tells the Windows kernel whether a particular executable supports high
entropy Address Space Layout Randomization (ASLR).
Syntax
-highentropyva[+ | -]
Arguments
+ | -
This option specifies that a 64-bit executable or an executable that is marked by the -platform:anycpu compiler
option supports a high entropy virtual address space. The option is disabled by default. Use -highentropyva+ or
-highentropyva to enable it.
Remarks
The -highentropyva option enables compatible versions of the Windows kernel to use higher degrees of entropy
when randomizing the address space layout of a process as part of ASLR. Using higher degrees of entropy means
that a larger number of addresses can be allocated to memory regions such as stacks and heaps. As a result, it is
more difficult to guess the location of a particular memory region.
When the -highentropyva compiler option is specified, the target executable and any modules that it depends on
must be able to handle pointer values that are larger than 4 gigabytes (GB) when they are running as a 64-bit
process.
-keycontainer (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
-keycontainer:string
Arguments
string
The name of the strong name key container.
Remarks
When the -keycontainer option is used, the compiler creates a sharable component. The compiler inserts a
public key from the specified container into the assembly manifest and signs the final assembly with the private
key. To generate a key file, type sn -k file at the command line. sn -i installs the key pair into a container. This
option is not supported when the compiler runs on CoreCLR. To sign an assembly when building on CoreCLR, use
the -keyfile option.
If you compile with -target:module, the name of the key file is held in the module and incorporated into the
assembly when you compile this module into an assembly with -addmodule.
You can also specify this option as a custom attribute (System.Reflection.AssemblyKeyNameAttribute) in the
source code for any Microsoft intermediate language (MSIL) module.
You can also pass your encryption information to the compiler with -keyfile. Use -delaysign if you want the public
key added to the assembly manifest but want to delay signing the assembly until it has been tested.
For more information, see Creating and Using Strong-Named Assemblies and Delay Signing an Assembly.
To set this compiler option in the Visual Studio development environment
1. This compiler option is not available in the Visual Studio development environment.
You can programmatically access this compiler option with AssemblyKeyContainerName.
See also
C# Compiler -keyfile option
C# Compiler Options
Managing Project and Solution Properties
-keyfile (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
-keyfile:file
Arguments
T ERM DEF IN IT IO N
file The name of the file containing the strong name key.
Remarks
When this option is used, the compiler inserts the public key from the specified file into the assembly manifest
and then signs the final assembly with the private key. To generate a key file, type sn -k file at the command
line.
If you compile with -target:module , the name of the key file is held in the module and incorporated into the
assembly that is created when you compile an assembly with -addmodule.
You can also pass your encryption information to the compiler with -keycontainer. Use -delaysign if you want a
partially signed assembly.
In case both -keyfile and -keycontainer are specified (either by command line option or by custom attribute) in
the same compilation, the compiler will first try the key container. If that succeeds, then the assembly is signed
with the information in the key container. If the compiler does not find the key container, it will try the file
specified with -keyfile. If that succeeds, the assembly is signed with the information in the key file and the key
information will be installed in the key container (similar to sn -i) so that on the next compilation, the key
container will be valid.
Note that a key file might contain only the public key.
For more information, see Creating and Using Strong-Named Assemblies and Delay Signing an Assembly.
To set this compiler option in the Visual Studio development environment
1. Open the Proper ties page for the project.
2. Click the Signing property page.
3. Modify the Choose a strong name key file property.
You can programmatically access this compiler option with AssemblyOriginatorKeyFile.
See also
C# Compiler Options
Managing Project and Solution Properties
-langversion (C# Compiler Options)
9/3/2020 • 3 minutes to read • Edit Online
Causes the compiler to accept only syntax that is included in the chosen C# language specification.
Syntax
-langversion:option
Arguments
option
VA L UE M EA N IN G
preview The compiler accepts all valid language syntax from the latest
preview version.
latest The compiler accepts syntax from the latest released version
of the compiler (including minor version).
latestMajor ( default ) The compiler accepts syntax from the latest released major
version of the compiler.
ISO-2 (or 2 ) The compiler accepts only syntax that is included in ISO/IEC
23270:2006 C# (2.0).
ISO-1 (or 1 ) The compiler accepts only syntax that is included in ISO/IEC
23270:2003 C# (1.0/1.2).
The default language version depends on the target framework for your application and the version of the SDK or
Visual Studio installed. Those rules are defined in the configuring the language version article.
Remarks
Metadata referenced by your C# application is not subject to -langversion compiler option.
Because each version of the C# compiler contains extensions to the language specification, -langversion does not
give you the equivalent functionality of an earlier version of the compiler.
Additionally, while C# version updates generally coincide with major .NET Framework releases, the new syntax and
features are not necessarily tied to that specific framework version. While the new features definitely require a
new compiler update that is also released alongside the C# revision, each specific feature has its own minimum
.NET API or common language runtime requirements that may allow it to run on downlevel frameworks by
including NuGet packages or other libraries.
Regardless of which -langversion setting you use, use the current version of the common language runtime to
create your .exe or .dll. One exception is friend assemblies and -moduleassemblyname (C# Compiler Option),
which work under -langversion:ISO-1 .
For other ways to specify the C# language version, see the Select the C# language version article.
For information about how to set this compiler option programmatically, see LanguageVersion.
C# language specification
VERSIO N L IN K DESC RIP T IO N
See also
C# Compiler Options
Managing Project and Solution Properties
-lib (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -lib option specifies the location of assemblies referenced by means of the -reference (C# Compiler Options)
option.
Syntax
-lib:dir1[,dir2]
Arguments
dir1
A directory for the compiler to look in if a referenced assembly is not found in the current working directory (the
directory from which you are invoking the compiler) or in the common language runtime's system directory.
dir2
One or more additional directories to search in for assembly references. Separate additional directory names with
a comma, and without white space between them.
Remarks
The compiler searches for assembly references that are not fully qualified in the following order:
1. Current working directory. This is the directory from which the compiler is invoked.
2. The common language runtime system directory.
3. Directories specified by -lib .
4. Directories specified by the LIB environment variable.
Use -reference to specify an assembly reference.
-lib is additive; specifying it more than once appends to any prior values.
An alternative to using -lib is to copy into the working directory any required assemblies; this will allow you to
simply pass the assembly name to -reference . You can then delete the assemblies from the working directory.
Since the path to the dependent assembly is not specified in the assembly manifest, the application can be started
on the target computer and will find and use the assembly in the global assembly cache.
Because the compiler can reference the assembly does not imply the common language runtime will be able to
find and load the assembly at runtime. See How the Runtime Locates Assemblies for details on how the runtime
searches for referenced assemblies.
To set this compiler option in the Visual Studio development environment
1. Open the project's Proper ty Pages dialog box.
2. Click the References Path property page.
3. Modify the contents of the list box.
For information on how to set this compiler option programmatically, see ReferencePath.
Example
Compile t2.cs to create an .exe file. The compiler will look in the working directory and in the root directory of the
C drive for assembly references.
See also
C# Compiler Options
Managing Project and Solution Properties
-link (C# Compiler Options)
9/3/2020 • 3 minutes to read • Edit Online
Causes the compiler to make COM type information in the specified assemblies available to the project that you
are currently compiling.
Syntax
-link:fileList
// -or-
-l:fileList
Arguments
fileList
Required. Comma-delimited list of assembly file names. If the file name contains a space, enclose the name in
quotation marks.
Remarks
The -link option enables you to deploy an application that has embedded type information. The application can
then use types in a runtime assembly that implement the embedded type information without requiring a
reference to the runtime assembly. If various versions of the runtime assembly are published, the application that
contains the embedded type information can work with the various versions without having to be recompiled. For
an example, see Walkthrough: Embedding Types from Managed Assemblies.
Using the -link option is especially useful when you are working with COM interop. You can embed COM types
so that your application no longer requires a primary interop assembly (PIA) on the target computer. The -link
option instructs the compiler to embed the COM type information from the referenced interop assembly into the
resulting compiled code. The COM type is identified by the CLSID (GUID) value. As a result, your application can
run on a target computer that has installed the same COM types with the same CLSID values. Applications that
automate Microsoft Office are a good example. Because applications like Office usually keep the same CLSID
value across different versions, your application can use the referenced COM types as long as .NET Framework 4
or later is installed on the target computer and your application uses methods, properties, or events that are
included in the referenced COM types.
The -link option embeds only interfaces, structures, and delegates. Embedding COM classes is not supported.
NOTE
When you create an instance of an embedded COM type in your code, you must create the instance by using the
appropriate interface. Attempting to create an instance of an embedded COM type by using the CoClass causes an error.
To set the -link option in Visual Studio, add an assembly reference and set the Embed Interop Types property to
true . The default for the Embed Interop Types property is false .
If you link to a COM assembly (Assembly A) which itself references another COM assembly (Assembly B), you also
have to link to Assembly B if either of the following is true:
A type from Assembly A inherits from a type or implements an interface from Assembly B.
A field, property, event, or method that has a return type or parameter type from Assembly B is invoked.
Like the -reference compiler option, the -link compiler option uses the Csc.rsp response file, which references
frequently used .NET Framework assemblies. Use the -noconfig compiler option if you do not want the compiler
to use the Csc.rsp file.
The short form of -link is -l .
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Interop.Excel;
In the following example, client code can call the method that returns the IList generic interface without error.
public class Client
{
public void Main()
{
Utility util = new Utility();
Example
The following code compiles source file OfficeApp.cs and reference assemblies from COMData1.dll and
COMData2.dll to produce OfficeApp.exe .
See also
C# Compiler Options
Walkthrough: Embedding Types from Managed Assemblies
-reference (C# Compiler Options)
-noconfig (C# Compiler Options)
Command-line Building With csc.exe
Interoperability Overview
-linkresource (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
Creates a link to a .NET Framework resource in the output file. The resource file is not added to the output file. This
differs from the -resource option which does embed a resource file in the output file.
Syntax
-linkresource:filename[,identifier[,accessibility-modifier]]
Arguments
filename
The .NET Framework resource file to which you want to link from the assembly.
identifier (optional)
The logical name for the resource; the name that is used to load the resource. The default is the name of the file.
accessibility-modifier (optional)
The accessibility of the resource: public or private. The default is public.
Remarks
By default, linked resources are public in the assembly when they are created with the C# compiler. To make the
resources private, specify private as the accessibility modifier. No other modifier other than public or private
is allowed.
-linkresource requires one of the -target options other than -target:module .
If filename is a .NET Framework resource file created, for example, by Resgen.exe or in the development
environment, it can be accessed with members in the System.Resources namespace. For more information, see
System.Resources.ResourceManager. For all other resources, use the GetManifestResource methods in the
Assembly class to access the resource at run time.
The file specified in filename can be any format. For example, you may want to make a native DLL part of the
assembly, so that it can be installed into the global assembly cache and accessed from managed code in the
assembly. The second of the following examples shows how to do this. You can do the same thing in the Assembly
Linker. The third of the following examples shows how to do this. For more information, see Al.exe (Assembly
Linker) and Working with Assemblies and the Global Assembly Cache.
-linkres is the short form of -linkresource .
This compiler option is unavailable in Visual Studio and cannot be changed programmatically.
Example
Compile in.cs and link to resource file rf.resource :
Example
This example does the same thing as the previous one, but by using Assembly Linker options.
See also
C# Compiler Options
Al.exe (Assembly Linker)
Working with Assemblies and the Global Assembly Cache
Managing Project and Solution Properties
-main (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
This option specifies the class that contains the entry point to the program, if more than one class contains a Main
method.
Syntax
-main:class
Arguments
class
The type that contains the Main method.
The provided class name must be fully qualified; it must include the full namespace containing the class, followed
by the class name. For example, when the Main method is located inside the Program class in the
MyApplication.Core namespace, the compiler option has to be -main:MyApplication.Core.Program .
Remarks
If your compilation includes more than one type with a Main method, you can specify which type contains the
Main method that you want to use as the entry point into the program.
This option is for use when compiling an .exe file.
To set this compiler option in the Visual Studio development environment
1. Open the project's Proper ties page.
2. Click the Application property page.
3. Modify the Star tup object property.
To set this compiler option programmatically, see StartupObject.
To set this compiler option by manually editing the .csproj file
You can set this option by editing the .csproj file and adding an element StartupObject inside the PropertyGroup
section. For example:
<PropertyGroup>
...
<StartupObject>MyApplication.Core.Program</StartupObject>
</PropertyGroup>
Example
Compile t2.cs and t3.cs , specifying that the Main method will be found in Test2 :
Syntax
-moduleassemblyname:assembly_name
Arguments
assembly_name
The name of the assembly whose non-public types the .netmodule can access.
Remarks
-moduleassemblyname should be used when building a .netmodule, and where the following conditions are
true:
The .netmodule needs access to non-public types in an existing assembly.
You know the name of the assembly into which the .netmodule will be built.
The existing assembly has granted friend assembly access to the assembly into which the .netmodule will be
built.
For more information on building a .netmodule, see -target:module (C# Compiler Options).
For more information on friend assemblies, see Friend Assemblies.
This option is not available from within the development environment; it is only available when compiling from the
command line.
This compiler option is unavailable in Visual Studio and cannot be changed programmatically.
Example
This sample builds an assembly with a private type, and that gives friend assembly access to an assembly called
csman_an_assembly.
// moduleassemblyname_1.cs
// compile with: -target:library
using System;
using System.Runtime.CompilerServices;
[assembly:InternalsVisibleTo ("csman_an_assembly")]
class An_Internal_Class
{
public void Test()
{
Console.WriteLine("An_Internal_Class.Test called");
}
}
Example
This sample builds a .netmodule that accesses a non-public type in the assembly moduleassemblyname_1.dll. By
knowing that this .netmodule will be built into an assembly called csman_an_assembly, we can specify -
moduleassemblyname , allowing the .netmodule to access non-public types in an assembly that has granted
friend assembly access to csman_an_assembly.
// moduleassemblyname_2.cs
// compile with: -moduleassemblyname:csman_an_assembly -target:module -reference:moduleassemblyname_1.dll
class B {
public void Test() {
An_Internal_Class x = new An_Internal_Class();
x.Test();
}
}
Example
This code sample builds the assembly csman_an_assembly, referencing the previously-built assembly and
.netmodule.
// csman_an_assembly.cs
// compile with: -addmodule:moduleassemblyname_2.netmodule -reference:moduleassemblyname_1.dll
class A {
public static void Main() {
B bb = new B();
bb.Test();
}
}
An_Internal_Class.Test called
See also
C# Compiler Options
Managing Project and Solution Properties
-noconfig (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -noconfig option tells the compiler not to compile with the csc.rsp file, which is located in and loaded from
the same directory as the csc.exe file.
Syntax
-noconfig
Remarks
The csc.rsp file references all the assemblies shipped with the .NET Framework. The actual references that the
Visual Studio .NET development environment includes depend on the project type.
You can modify the csc.rsp file and specify additional compiler options that should be included in every
compilation from the command line with csc.exe (except the -noconfig option).
The compiler processes the options passed to the csc command last. Therefore, any option on the command line
overrides the setting of the same option in the csc.rsp file.
If you do not want the compiler to look for and use the settings in the csc.rsp file, specify -noconfig .
This compiler option is unavailable in Visual Studio and cannot be changed programmatically.
See also
C# Compiler Options
Managing Project and Solution Properties
-nologo (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -nologo option suppresses display of the sign-on banner when the compiler starts up and display of
informational messages during compiling.
Syntax
-nologo
Remarks
This option is not available from within the development environment; it is only available when compiling from the
command line.
This compiler option is unavailable in Visual Studio and cannot be changed programmatically.
See also
C# Compiler Options
Managing Project and Solution Properties
-nostdlib (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
-nostdlib prevents the import of mscorlib.dll, which defines the entire System namespace.
Syntax
-nostdlib[+ | -]
Remarks
Use this option if you want to define or create your own System namespace and objects.
If you do not specify -nostdlib , mscorlib.dll is imported into your program (same as specifying -nostdlib- ).
Specifying -nostdlib is the same as specifying -nostdlib+ .
To set this compiler option in Visual Studio
NOTE
The following instructions apply to Visual Studio 2015 (and earlier versions) only. The Do not reference mscorlib.dll build
property doesn't exist in newer versions of Visual Studio.
See also
C# Compiler Options
-nowarn (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -nowarn option lets you suppress the compiler from displaying one or more warnings. Separate multiple
warning numbers with a comma.
Syntax
-nowarn:number1[,number2,...]
Arguments
number1, number2
Warning number(s) that you want the compiler to suppress.
Remarks
You should only specify the numeric part of the warning identifier. For example, if you want to suppress CS0028,
you could specify -nowarn:28 .
The compiler will silently ignore warning numbers passed to -nowarn that were valid in previous releases, but that
have been removed from the compiler. For example, CS0679 was valid in the compiler in Visual Studio .NET 2002
but was subsequently removed.
The following warnings cannot be suppressed by the -nowarn option:
Compiler Warning (level 1) CS2002
Compiler Warning (level 1) CS2023
Compiler Warning (level 1) CS2029
To set this compiler option in the Visual Studio development environment
1. Open the Proper ties page for the project. For details, see Build Page, Project Designer (C#).
2. Click the Build property page.
3. Modify the Suppress Warnings property.
For information about how to set this compiler option programmatically, see DelaySign.
See also
C# Compiler Options
Managing Project and Solution Properties
C# Compiler Errors
-nowin32manifest (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
Use the -nowin32manifest option to instruct the compiler not to embed any application manifest into the
executable file.
Syntax
-nowin32manifest
Remarks
When this option is used, the application will be subject to virtualization on Windows Vista unless you provide an
application manifest in a Win32 Resource file or during a later build step.
In Visual Studio, set this option in the Application Proper ty page by selecting the Create Application Without
a Manifest option in the Manifest drop down list. For more information, see Application Page, Project Designer
(C#).
For more information about manifest creation, see -win32manifest (C# Compiler Options).
See also
C# Compiler Options
Managing Project and Solution Properties
-nullable (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -nullable option lets you specify the desired nullable context.
Syntax
-nullable[+ | -]
-nullable:{enable | disable | warnings | annotations}
Arguments
+ | -
Specifying + , or just -nullable , causes the compiler to enable nullable context. Specifying - , which is in effect if
you do not specify -nullable , disables nullable context.
enable | disable | warnings | annotations
Specifies the nullable context option. Similar to + or - , to enable and disable, but allows for more granularity of
nullable context specificity. The enable argument, which is in effect the same as if you specify -nullable , enables
the nullable context. Specifying disable will disable nullable context. When providing the warnings argument, -
nullable:warnings , the nullable warning context is enabled. When specifying the annotations argument, -
nullable:annotations , the nullable annotation context is enabled.
Remarks
Flow analysis is used to infer the nullability of variables within executable code. The inferred nullability of a
variable is independent of the variable's declared nullability. Method calls are analyzed even when they are
conditionally omitted. For instance, Debug.Assert in release mode.
Invocation of methods annotated with the following attributes will also affect flow analysis:
Simple pre-conditions: AllowNullAttribute and DisallowNullAttribute
Simple post-conditions: MaybeNullAttribute and NotNullAttribute
Conditional post-conditions: MaybeNullWhenAttribute and NotNullWhenAttribute
DoesNotReturnIfAttribute (for example, DoesNotReturnIf(false) for Debug.Assert) and DoesNotReturnAttribute
NotNullIfNotNullAttribute
Member post-conditions: MemberNotNullAttribute(String) and MemberNotNullAttribute(String[])
To set this compiler option in a project
Edit the .csproj file to add the <Nullable> tag within a Project/PropertyGroup hierarchy:
<Project Sdk="...">
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
See also
C# Compiler Options
Nullable reference types
-optimize (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -optimize option enables or disables optimizations performed by the compiler to make your output file
smaller, faster, and more efficient.
Syntax
-optimize[+ | -]
Remarks
-optimize also tells the common language runtime to optimize code at runtime.
By default, optimizations are disabled. Specify -optimize+ to enable optimizations.
When building a module to be used by an assembly, use the same -optimize settings as those of the assembly.
-o is the short form of -optimize .
It is possible to combine the -optimize and -debug options.
To set this compiler option in the Visual Studio development environment
1. Open the project's Proper ties page.
2. Click the Build property page.
3. Modify the Optimize Code property.
For information on how to set this compiler option programmatically, see Optimize.
Example
Compile t2.cs and enable compiler optimizations:
See also
C# Compiler Options
Managing Project and Solution Properties
-out (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
-out:filename
Arguments
filename
The name of the output file created by the compiler.
Remarks
On the command line, it is possible to specify multiple output files for your compilation. The compiler expects to
find one or more source code files following the -out option. Then, all source code files will be compiled into the
output file specified by that -out option.
Specify the full name and extension of the file you want to create.
If you do not specify the name of the output file:
An .exe will take its name from the source code file that contains the Main method.
A .dll or .netmodule will take its name from the first source code file.
A source code file used to compile one output file cannot be used in the same compilation for the compilation of
another output file.
When producing multiple output files in a command-line compilation, keep in mind that only one of the output
files can be an assembly and that only the first output file specified (implicitly or explicitly with -out ) can be the
assembly.
Any modules produced as part of a compilation become files associated with any assembly also produced in the
compilation. Use ildasm.exe to view the assembly manifest to see the associated files.
The -out compiler option is required in order for an exe to be the target of a friend assembly. For more
information see Friend Assemblies.
To set this compiler option in the Visual Studio development environment
1. Open the project's Proper ties page.
2. Click the Application property page.
3. Modify the Assembly name property.
To set this compiler option programmatically: the OutputFileName is a read-only property, which is
determined by a combination of the project type (exe, library, and so forth) and the assembly name.
Modifying one or both of these properties will be necessary to set the output file name.
Example
Compile t.csand create output file t.exe , as well as build t2.cs and create module output file
mymodule.netmodule :
See also
C# Compiler Options
Friend Assemblies
Managing Project and Solution Properties
-pathmap (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -pathmap compiler option specifies how to map physical paths to source path names output by the compiler.
Syntax
-pathmap:path1=sourcePath1,path2=sourcePath2
Arguments
path1 The full path to the source files in the current environment
sourcePath1 The source path substituted for path1 in any output files.
To specify multiple mapped source paths, separate each with a comma.
Remarks
The compiler writes the source path into its output for the following reasons:
1. The source path is substituted for an argument when the CallerFilePathAttribute is applied to an optional
parameter.
2. The source path is embedded in a PDB file.
3. The path of the PDB file is embedded into a PE (portable executable) file.
This option maps each physical path on the machine where the compiler runs to a corresponding path that should
be written in the output files.
Example
Compile t.cs in the directory C:\work\tests and map that directory to \publish in the output:
See also
C# Compiler Options
Managing Project and Solution Properties
-pdb (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -pdb compiler option specifies the name and location of the debug symbols file.
Syntax
-pdb:filename
Arguments
filename
The name and location of the debug symbols file.
Remarks
When you specify -debug (C# Compiler Options), the compiler will create a .pdb file in the same directory where
the compiler will create the output file (.exe or .dll) with a file name that is the same as the name of the output file.
-pdb allows you to specify a non-default file name and location for the .pdb file.
This compiler option cannot be set in the Visual Studio development environment, nor can it be changed
programmatically.
Example
Compile t.cs and create a .pdb file called tt.pdb:
See also
C# Compiler Options
Managing Project and Solution Properties
-platform (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
Specifies which version of the Common Language Runtime (CLR) can run the assembly.
Syntax
-platform:string
Parameters
string
anycpu (default), anycpu32bitpreferred, ARM, x64, x86, or Itanium.
Remarks
anycpu (default) compiles your assembly to run on any platform. Your application runs as a 64-bit process
whenever possible and falls back to 32-bit when only that mode is available.
anycpu32bitpreferred compiles your assembly to run on any platform. Your application runs in 32-bit
mode on systems that support both 64-bit and 32-bit applications. You can specify this option only for
projects that target the .NET Framework 4.5.
ARM compiles your assembly to run on a computer that has an Advanced RISC Machine (ARM) processor.
ARM64 compiles your assembly to run by the 64-bit CLR on a computer that has an Advanced RISC
Machine (ARM) processor that supports the A64 instruction set.
x64 compiles your assembly to be run by the 64-bit CLR on a computer that supports the AMD64 or
EM64T instruction set.
x86 compiles your assembly to be run by the 32-bit, x86-compatible CLR.
Itanium compiles your assembly to be run by the 64-bit CLR on a computer with an Itanium processor.
On a 64-bit Windows operating system:
Assemblies compiled with -platform:x86 execute on the 32-bit CLR running under WOW64.
A DLL compiled with the -platform:anycpu executes on the same CLR as the process into which it is
loaded.
Executables that are compiled with the -platform:anycpu execute on the 64-bit CLR.
Executables compiled with -platform:anycpu32bitpreferred execute on the 32-bit CLR.
The anycpu32bitpreferred setting is valid only for executable (.EXE) files, and it requires the .NET Framework 4.5.
For more information about developing an application to run on a Windows 64-bit operating system, see 64-bit
Applications.
To set this compiler option in the Visual Studio development environment
1. Open the Proper ties page for the project.
2. Click the Build property page.
3. Modify the Platform target property and, for projects that target the .NET Framework 4.5, select or clear
the Prefer 32-bit check box.
NOTE
-platform is not available in the development environment in Visual C# Express.
For information on how to set this compiler option programmatically, see PlatformTarget.
Example
The following example shows how to use the -platform option to specify that the application should be run by
the 64-bit CLR on a 64-bit Windows operating system.
See also
C# Compiler Options
Managing Project and Solution Properties
-preferreduilang (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
By using the -preferreduilang compiler option, you can specify the language in which the C# compiler displays
output, such as error messages.
Syntax
-preferreduilang: language
Arguments
language
The language name of the language to use for compiler output.
Remarks
You can use the -preferreduilang compiler option to specify the language that you want the C# compiler to use
for error messages and other command-line output. If the language pack for the language is not installed, the
language setting of the operating system is used instead, and no error is reported.
csc.exe -preferreduilang:ja-JP
Requirements
See also
C# Compiler Options
-publicsign (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
This option causes the compiler to apply a public key but does not actually sign the assembly. The -publicsign
option also sets a bit in the assembly that tells the runtime that the file is actually signed.
Syntax
-publicsign
Arguments
None.
Remarks
The -publicsign option requires the use of the -keyfile or -keycontainer. The keyfile or keycontainer options
specify the public key.
The -publicsign and -delaysign options are mutually exclusive.
Sometimes called "fake sign" or "OSS sign", public signing includes the public key in an output assembly and sets
the "signed" flag, but doesn't actually sign the assembly with a private key. This is useful for open source projects
where people want to build assemblies which are compatible with the released "fully signed" assemblies, but don't
have access to the private key used to sign the assemblies. Since almost no consumers actually need to check if
the assembly is fully signed, these publicly built assemblies are useable in almost every scenario where the fully
signed one would be used.
To set this compiler option in a csproj file
Open the .csproj file for a project, and add the following element:
<PublicSign>true</PublicSign>
See also
C# Compiler -delaysign option
C# Compiler -keyfile option
C# Compiler -keycontainer option
C# Compiler Options
Managing Project and Solution Properties
-recurse (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -recurse option enables you to compile source code files in all child directories of either the specified directory
(dir) or of the project directory.
Syntax
-recurse:[dir\]file
Arguments
dir (optional)
The directory in which you want the search to begin. If this is not specified, the search begins in the project
directory.
file
The file(s) to search for. Wildcard characters are allowed.
Remarks
The -recurse option lets you compile source code files in all child directories of either the specified directory ( dir
) or of the project directory.
You can use wildcards in a file name to compile all matching files in the project directory without using -recurse .
This compiler option is unavailable in Visual Studio and cannot be changed programmatically.
Example
Compiles all C# files in the current directory:
csc *.cs
Compiles all of the C# files in the dir1\dir2 directory and any directories below it and generates dir2.dll:
See also
C# Compiler Options
Managing Project and Solution Properties
-reference (C# Compiler Options)
9/3/2020 • 3 minutes to read • Edit Online
The -reference option causes the compiler to import public type information in the specified file into the current
project, thus enabling you to reference metadata from the specified assembly files.
Syntax
-reference:[alias=]filename
-reference:filename
Arguments
filename
The name of a file that contains an assembly manifest. To import more than one file, include a separate -
reference option for each file.
alias
A valid C# identifier that will represent a root namespace that will contain all namespaces in the assembly.
Remarks
To import from more than one file, include a -reference option for each file.
The files you import must contain a manifest; the output file must have been compiled with one of the -target
options other than -target:module.
-r is the short form of -reference .
Use -addmodule to import metadata from an output file that does not contain an assembly manifest.
If you reference an assembly (Assembly A) that references another assembly (Assembly B), you will need to
reference Assembly B if:
A type you use from Assembly A inherits from a type or implements an interface from Assembly B.
You invoke a field, property, event, or method that has a return type or parameter type from Assembly B.
Use -lib to specify the directory in which one or more of your assembly references is located. The -lib topic also
discusses the directories in which the compiler searches for assemblies.
In order for the compiler to recognize a type in an assembly, and not in a module, it needs to be forced to resolve
the type, which you can do by defining an instance of the type. There are other ways to resolve type names in an
assembly for the compiler: for example, if you inherit from a type in an assembly, the type name will then be
recognized by the compiler.
Sometimes it is necessary to reference two different versions of the same component from within one assembly.
To do this, use the alias suboption on the -reference switch for each file to distinguish between the two files.
This alias will be used as a qualifier for the component name, and will resolve to the component in one of the
files.
The csc response (.rsp) file, which references commonly used .NET Framework assemblies, is used by default. Use
-noconfig if you do not want the compiler to use csc.rsp.
NOTE
In Visual Studio, use the Add Reference dialog box. For more information, see How to: Add or Remove References By
Using the Reference Manager. To ensure equivalent behavior between adding references by using -reference and
adding references by using the Add Reference dialog box, set the Embed Interop Types property to False for the
assembly that you're adding. True is the default value for the property.
Example
This example shows how to use the extern alias feature.
You compile the source file and import metadata from grid.dll and grid20.dll , which have been compiled
previously. The two DLLs contain separate versions of the same component, and you use two -reference with
alias options to compile the source file. The options look like this:
-reference:GridV1=grid.dll -reference:GridV2=grid20.dll
This sets up the external aliases GridV1 and GridV2 , which you use in your program by means of an extern
statement:
Once this is done, you can refer to the grid control from grid.dll by prefixing the control name with GridV1 ,
like this:
GridV1::Grid
In addition, you can refer to the grid control from grid20.dll by prefixing the control name with GridV2 like
this:
GridV2::Grid
See also
C# Compiler Options
Managing Project and Solution Properties
-refout (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -refout option specifies a file path where the reference assembly should be output. This translates to
metadataPeStream in the Emit API. This option corresponds to the ProduceReferenceAssembly project property of
MSBuild.
Syntax
-refout:filepath
Arguments
filepath The filepath for the reference assembly. It should generally match that of the primary assembly. The
recommended convention (used by MSBuild) is to place the reference assembly in a "ref/" sub-folder relative to
the primary assembly.
Remarks
Reference assemblies are a special type of assembly that contain only the minimum amount of metadata required
to represent the library's public API surface. They include declarations for all members that are significant when
referencing an assembly in build tools, but exclude all member implementations and declarations of private
members that have no observable impact on their API contract. For more information, see Reference assemblies in
.NET Guide.
The -refout and -refonly options are mutually exclusive.
See also
C# Compiler Options
Managing Project and Solution Properties
-refonly (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -refonly option indicates that a reference assembly should be output instead of an implementation assembly,
as the primary output. The -refonly parameter silently disables outputting PDBs, as reference assemblies cannot
be executed. This option corresponds to the ProduceOnlyReferenceAssembly project property of MSBuild.
Syntax
-refonly
Remarks
Reference assemblies are a special type of assembly that contain only the minimum amount of metadata required
to represent the library's public API surface. They include declarations for all members that are significant when
referencing an assembly in build tools, but exclude all member implementations and declarations of private
members that have no observable impact on their API contract. For more information, see Reference assemblies in
.NET Guide.
The -refonly and -refout options are mutually exclusive.
See also
C# Compiler Options
Managing Project and Solution Properties
-resource (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
-resource:filename[,identifier[,accessibility-modifier]]
Arguments
filename
The .NET Framework resource file that you want to embed in the output file.
identifier (optional)
The logical name for the resource; the name that is used to load the resource. The default is the name of the file
name.
accessibility-modifier (optional)
The accessibility of the resource: public or private. The default is public.
Remarks
Use -linkresource to link a resource to an assembly and not add the resource file to the output file.
By default, resources are public in the assembly when they are created by using the C# compiler. To make the
resources private, specify private as the accessibility modifier. No other accessibility other than public or
private is allowed.
If filename is a .NET Framework resource file created, for example, by Resgen.exe or in the development
environment, it can be accessed with members in the System.Resources namespace. For more information, see
System.Resources.ResourceManager. For all other resources, use the GetManifestResource methods in the
Assembly class to access the resource at run time.
-res is the short form of -resource .
The order of the resources in the output file is determined from the order specified on the command line.
To set this compiler option in the Visual Studio development environment
1. Add a resource file to your project.
2. Select the file that you want to embed in Solution Explorer .
3. Select Build Action for the file in the Proper ties window.
4. Set Build Action to Embedded Resource .
For information about how to set this compiler option programmatically, see BuildAction.
Example
Compile in.cs and attach resource file rf.resource :
csc -resource:rf.resource in.cs
See also
C# Compiler Options
Managing Project and Solution Properties
-subsystemversion (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
Specifies the minimum version of the subsystem on which the generated executable file can run, thereby
determining the versions of Windows on which the executable file can run. Most commonly, this option ensures
that the executable file can leverage particular security features that aren’t available with older versions of
Windows.
NOTE
To specify the subsystem itself, use the -target compiler option.
Syntax
-subsystemversion:major.minor
Parameters
major.minor
The minimum required version of the subsystem, as expressed in a dot notation for major and minor versions. For
example, you can specify that an application can't run on an operating system that's older than Windows 7 if you
set the value of this option to 6.01, as the table later in this topic describes. You must specify the values for major
and minor as integers.
Leading zeroes in the minor version don't change the version, but trailing zeroes do. For example, 6.1 and 6.01
refer to the same version, but 6.10 refers to a different version. We recommend expressing the minor version as
two digits to avoid confusion.
Remarks
The following table lists common subsystem versions of Windows.
Windows XP 5.01
Windows 7 6.01
Windows 8 6.02
Default values
The default value of the -subsystemversion compiler option depends on the conditions in the following list:
The default value is 6.02 if any compiler option in the following list is set:
-target:appcontainerexe
-target:winmdobj
-platform:arm
The default value is 6.00 if you're using MSBuild, you're targeting .NET Framework 4.5, and you haven't set
any of the compiler options that were specified earlier in this list.
The default value is 4.00 if none of the previous conditions is true.
See also
C# Compiler Options
-target (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -target compiler option can be specified in one of the following forms:
-target:appcontainerexe
To create an .exe file for Windows 8.x Store apps.
-target:exe
To create an .exe file.
-target:library
To create a code library.
-target:module
To create a module.
-target:winexe
To create a Windows program.
-target:winmdobj
To create an intermediate .winmdobj file.
Unless you specify -target:module , -target causes a .NET Framework assembly manifest to be placed in an
output file. For more information, see Assemblies in .NET and Common Attributes.
The assembly manifest is placed in the first .exe output file in the compilation or in the first DLL, if there is no .exe
output file. For example, in the following command line, the manifest will be placed in 1.exe :
The compiler creates only one assembly manifest per compilation. Information about all files in a compilation is
placed in the assembly manifest. All output files except those created with -target:module can contain an
assembly manifest. When producing multiple output files at the command line, only one assembly manifest can
be created and it must go into the first output file specified on the command line. No matter what the first output
file is (-target:exe , -target:winexe , -target:librar y or -target:module ), any other output files produced in the
same compilation must be modules (-target:module ).
If you create an assembly, you can indicate that all or part of your code is CLS compliant with the
CLSCompliantAttribute attribute.
// target_clscompliant.cs
[assembly:System.CLSCompliant(true)] // specify assembly compliance
For more information about setting this compiler option programmatically, see OutputType.
See also
C# Compiler Options
Managing Project and Solution Properties
-subsystemversion (C# Compiler Options)
-target:appcontainerexe (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
If you use the -target:appcontainerexe compiler option, the compiler creates a Windows executable (.exe) file
that must be run in an app container. This option is equivalent to -target:winexe but is designed for Windows 8.x
Store apps.
Syntax
-target:appcontainerexe
Remarks
To require the app to run in an app container, this option sets a bit in the Portable Executable (PE) file. When that
bit is set, an error occurs if the CreateProcess method tries to launch the executable file outside an app container.
Unless you use the -out option, the output file name takes the name of the input file that contains the Main
method.
When you specify this option at a command prompt, all files until the next -out or -target option are used to
create the executable file.
To set this compiler option in the IDE
1. In Solution Explorer , open the shortcut menu for your project, and then choose Proper ties .
2. On the Application tab, in the Output type list, choose Windows Store App .
This option is available only for Windows 8.x Store app templates.
For information about how to set this compiler option programmatically, see OutputType.
Example
The following command compiles filename.cs into a Windows executable file that can be run only in an app
container.
See also
-target (C# Compiler Options)
-target:winexe (C# Compiler Options)
C# Compiler Options
-target:exe (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -target:exe option causes the compiler to create an executable (EXE), console application.
Syntax
-target:exe
Remarks
The -target:exe option is in effect by default. The executable file will be created with the .exe extension.
Use -target:winexe to create a Windows program executable.
Unless otherwise specified with the -out option, the output file name takes the name of the input file that contains
the Main method.
When specified at the command line, all files up to the next -out or -target:module option are used to create the
.exe file
One and only one Main method is required in the source code files that are compiled into an .exe file. The -main
compiler option lets you specify which class contains the Main method, in cases where your code has more than
one class with a Main method.
To set this compiler option in the Visual Studio development environment
1. Open the project's Proper ties page.
2. Click the Application property page.
3. Modify the Output type property.
For information on how to set this compiler option programmatically, see OutputType.
Example
Each of the following command lines will compile in.cs , creating in.exe :
See also
-target (C# Compiler Options)
C# Compiler Options
-target:library (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -target:librar y option causes the compiler to create a dynamic-link library (DLL) rather than an executable
file (EXE).
Syntax
-target:library
Remarks
The DLL will be created with the .dll extension.
Unless otherwise specified with the -out option, the output file name takes the name of the first input file.
When specified at the command line, all files up to the next -out or -target:module option are used to create the
.dll file.
When building a .dll file, a Main method is not required.
To set this compiler option in the Visual Studio development environment
1. Open the project's Proper ties page.
2. Click the Application property page.
3. Modify the Output type property.
For information on how to set this compiler option programmatically, see OutputType.
Example
Compile in.cs , creating in.dll :
See also
-target (C# Compiler Options)
C# Compiler Options
-target:module (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
-target:module
Remarks
By default, the output file created by compiling with this option will have an extension of .netmodule.
A file that does not have an assembly manifest cannot be loaded by the .NET Framework common language
runtime. However, such a file can be incorporated into the assembly manifest of an assembly by means of -
addmodule.
If more than one module is created in a single compilation, internal types in one module will be available to other
modules in the compilation. When code in one module references internal types in another module, then both
modules must be incorporated into an assembly manifest, by means of -addmodule .
Creating a module is not supported in the Visual Studio development environment.
For information on how to set this compiler option programmatically, see OutputType.
Example
Compile in.cs , creating in.netmodule :
See also
-target (C# Compiler Options)
C# Compiler Options
-target:winexe (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -target:winexe option causes the compiler to create an executable (EXE), Windows program.
Syntax
-target:winexe
Remarks
The executable file will be created with the .exe extension. A Windows program is one that provides a user
interface from either the .NET Framework library or with the Windows APIs.
Use -target:exe to create a console application.
Unless otherwise specified with the -out option, the output file name takes the name of the input file that contains
the Main method.
When specified at the command line, all files until the next -out or -target option are used to create the Windows
program.
One and only one Main method is required in the source code files that are compiled into an .exe file. The -main
option lets you specify which class contains the Main method, in cases where your code has more than one class
with a Main method.
To set this compiler option in the Visual Studio development environment
1. Open the project's Proper ties page.
2. Click the Application property page.
3. Modify the Output type property.
For information on how to set this compiler option programmatically, see OutputType.
Example
Compile in.cs into a Windows program:
See also
-target (C# Compiler Options)
C# Compiler Options
-target:winmdobj (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
If you use the -target:winmdobj compiler option, the compiler creates an intermediate .winmdobj file that you
can convert to a Windows Runtime binary (.winmd) file. The .winmd file can then be consumed by JavaScript and
C++ programs, in addition to managed language programs.
Syntax
-target:winmdobj
Remarks
The winmdobj setting signals to the compiler that an intermediate module is required. In response, Visual Studio
compiles the C# class library as a .winmdobj file. The .winmdobj file can then be fed through the WinMDExp
export tool to produce a Windows metadata (.winmd) file. The .winmd file contains both the code from the original
library and the WinMD metadata that is used by JavaScript or C++ and by the Windows Runtime.
The output of a file that’s compiled by using the -target:winmdobj compiler option is designed to be used only
as input for the WimMDExp export tool; the .winmdobj file itself isn’t referenced directly.
Unless you use the -out option, the output file name takes the name of the first input file. A Main method isn’t
required.
If you specify the -target:winmdobj option at a command prompt, all files until the next -out or -target:module
option are used to create the Windows program.
To set this compiler option in the Visual Studio IDE for a Windows Store app
1. In Solution Explorer , open the shortcut menu for your project, and then choose Proper ties .
2. Choose the Application tab.
3. In the Output type list, choose WinMD File .
The WinMD File option is available only for Windows 8.x Store app templates.
For information about how to set this compiler option programmatically, see OutputType.
Example
The following command compiles filename.cs into an intermediate .winmdobj file.
See also
-target (C# Compiler Options)
C# Compiler Options
-unsafe (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -unsafe compiler option allows code that uses the unsafe keyword to compile.
Syntax
-unsafe
Remarks
For more information about unsafe code, see Unsafe Code and Pointers.
To set this compiler option in the Visual Studio development environment
1. Open the project's Proper ties page.
2. Click the Build property page.
3. Select the Allow Unsafe Code check box.
To add this option in a csproj file
Open the .csproj file for a project, and add the following elements:
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
For information about how to set this compiler option programmatically, see AllowUnsafeBlocks.
Example
Compile in.cs for unsafe mode:
See also
C# Compiler Options
Managing Project and Solution Properties
-utf8output (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
-utf8output
Remarks
In some international configurations, compiler output cannot correctly be displayed in the console. In these
configurations, use -utf8output and redirect compiler output to a file.
This compiler option is unavailable in Visual Studio and cannot be changed programmatically.
See also
C# Compiler Options
-warn (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -warn option specifies the warning level for the compiler to display.
Syntax
-warn:option
Arguments
option
The warning level you want displayed for the compilation: Lower numbers show only high severity warnings;
higher numbers show more warnings. The value must be zero or a positive integer:
WA RN IN G L EVEL M EA N IN G
Greater than 5 Any value greater than 5 will be treated as 5. You generally
put arbitrary large value (for example, 9999 ) to make sure
you always have all warnings if the compiler is updated with
new warning levels.
Remarks
To get information about an error or warning, you can look up the error code in the Help Index. For other ways to
get information about an error or warning, see C# Compiler Errors.
Use -warnaserror to treat all warnings as errors. Use -nowarn to disable certain warnings.
-w is the short form of -warn .
To set this compiler option in the Visual Studio development environment
1. Open the project's Proper ties page.
2. Click the Build property page.
3. Modify the Warning Level property.
For information on how to set this compiler option programmatically, see WarningLevel.
Example
Compile in.cs and have the compiler only display level 1 warnings:
See also
C# Compiler Options
Managing Project and Solution Properties
-warnaserror (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
-warnaserror[+ | -][:warning-list]
Remarks
Any messages that would ordinarily be reported as warnings are instead reported as errors, and the build process
is halted (no output files are built).
By default, -warnaserror- is in effect, which causes warnings to not prevent the generation of an output file. -
warnaserror , which is the same as -warnaserror+ , causes warnings to be treated as errors.
Optionally, if you want only a few specific warnings to be treated as errors, you may specify a comma-separated
list of warning numbers to treat as errors. The set of all nullability warnings can be specified with the nullable
shorthand.
Use -warn to specify the level of warnings that you want the compiler to display. Use -nowarn to disable certain
warnings.
To set this compiler option in the Visual Studio development environment
1. Open the project's Proper ties page.
2. Click the Build property page.
3. Modify the Treat Warnings As Errors property.
To set this compiler option programmatically, see TreatWarningsAsErrors.
Example
Compile in.cs and have the compiler display no warnings:
See also
C# Compiler Options
Managing Project and Solution Properties
-win32icon (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
The -win32icon option inserts an .ico file in the output file, which gives the output file the desired appearance in
the File Explorer.
Syntax
-win32icon:filename
Arguments
filename
The .ico file that you want to add to your output file.
Remarks
An .ico file can be created with the Resource Compiler. The Resource Compiler is invoked when you compile a
Visual C++ program; an .ico file is created from the .rc file.
See -linkresource (to reference) or -resource (to attach) a .NET Framework resource file. See -win32res to import a
.res file.
To set this compiler option in the Visual Studio development environment
1. Open the project's Proper ties pages.
2. Click the Application property page.
3. Modify the Application icon property.
For information on how to set this compiler option programmatically, see ApplicationIcon.
Example
Compile in.cs and attach an .ico file rf.ico to produce in.exe :
See also
C# Compiler Options
Managing Project and Solution Properties
-win32manifest (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
Use the -win32manifest option to specify a user-defined Win32 application manifest file to be embedded into a
project's portable executable (PE) file.
Syntax
-win32manifest: filename
Arguments
filename
The name and location of the custom manifest file.
Remarks
By default, the Visual C# compiler embeds an application manifest that specifies a requested execution level of
"asInvoker." It creates the manifest in the same folder in which the executable is built, typically the bin\Debug or
bin\Release folder when you use Visual Studio. If you want to supply a custom manifest, for example to specify a
requested execution level of "highestAvailable" or "requireAdministrator," use this option to specify the name of the
file.
NOTE
This option and the -win32res (C# Compiler Options) option are mutually exclusive. If you try to use both options in the
same command line you will get a build error.
An application that has no application manifest that specifies a requested execution level will be subject to
file/registry virtualization under the User Account Control feature in Windows. For more information, see User
Account Control.
Your application will be subject to virtualization if either of these conditions is true:
You use the -nowin32manifest option and you do not provide a manifest in a later build step or as part of
a Windows Resource (.res) file by using the -win32res option.
You provide a custom manifest that does not specify a requested execution level.
Visual Studio creates a default .manifest file and stores it in the debug and release directories alongside the
executable file. You can add a custom manifest by creating one in any text editor and then adding the file to the
project. Alternatively, you can right-click the Project icon in Solution Explorer , click Add New Item , and then
click Application Manifest File . After you have added your new or existing manifest file, it will appear in the
Manifest drop down list. For more information, see Application Page, Project Designer (C#).
You can provide the application manifest as a custom post-build step or as part of a Win32 resource file by using
the -nowin32manifest (C# Compiler Options) option. Use that same option if you want your application to be
subject to file or registry virtualization on Windows Vista. This will prevent the compiler from creating and
embedding a default manifest in the portable executable (PE) file.
Example
The following example shows the default manifest that the Visual C# compiler inserts into a PE.
NOTE
The compiler inserts a standard application name " MyApplication.app " into the xml. This is a workaround to enable
applications to run on Windows Server 2003 Service Pack 3.
See also
C# Compiler Options
-nowin32manifest (C# Compiler Options)
Managing Project and Solution Properties
-win32res (C# Compiler Options)
9/3/2020 • 2 minutes to read • Edit Online
Syntax
-win32res:filename
Arguments
filename
The resource file that you want to add to your output file.
Remarks
A Win32 resource file can be created with the Resource Compiler. The Resource Compiler is invoked when you
compile a Visual C++ program; a .res file is created from the .rc file.
A Win32 resource can contain version or bitmap (icon) information that would help identify your application in the
File Explorer. If you do not specify -win32res , the compiler will generate version information based on the
assembly version.
See -linkresource (to reference) or -resource (to attach) a .NET Framework resource file.
To set this compiler option in the Visual Studio development environment
1. Open the project's Proper ties page.
2. Click the Application property page.
3. Click on the Resource File button and choose a file by using the combo box.
Example
Compile in.cs and attach a Win32 resource file rf.res to produce in.exe :
See also
C# Compiler Options
Managing Project and Solution Properties
C# Compiler Errors
9/3/2020 • 2 minutes to read • Edit Online
Some C# compiler errors have corresponding topics that explain why the error is generated, and, in some cases,
how to fix the error. Use one of the following steps to see whether help is available for a particular error message.
Find the error number (for example, CS0029) in the Output Window, and then search for it on Microsoft
Docs.
Choose the error number (for example, CS0029) in the Output Window, and then choose the F1 key.
In the Index, enter the error number in the Look for box.
If none of these steps leads to information about your error, go to the end of this page, and send feedback that
includes the number or text of the error.
For information about how to configure error and warning options in C#, see Build Page, Project Designer (C#).
NOTE
Your computer might show different names or locations for some of the Visual Studio user interface elements in the
following instructions. The Visual Studio edition that you have and the settings that you use determine these elements. For
more information, see Personalizing the IDE.
See also
C# Compiler Options
Sorry, we don't have specifics on this C# error
Build Page, Project Designer (C#)
-warn (C# Compiler Options)
-nowarn (C# Compiler Options)
Introduction
9/3/2020 • 55 minutes to read • Edit Online
Hello world
The "Hello, World" program is traditionally used to introduce a programming language. Here it
is in C#:
using System;
class Hello
{
static void Main() {
Console.WriteLine("Hello, World");
}
}
C# source files typically have the file extension .cs . Assuming that the "Hello, World" program
is stored in the file hello.cs , the program can be compiled with the Microsoft C# compiler
using the command line
csc hello.cs
which produces an executable assembly named hello.exe . The output produced by this
application when it is run is
Hello, World
The "Hello, World" program starts with a using directive that references the System
namespace. Namespaces provide a hierarchical means of organizing C# programs and libraries.
Namespaces contain types and other namespaces—for example, the System namespace
contains a number of types, such as the Console class referenced in the program, and a
number of other namespaces, such as IO and Collections . A using directive that references
a given namespace enables unqualified use of the types that are members of that namespace.
Because of the using directive, the program can use Console.WriteLine as shorthand for
System.Console.WriteLine .
The Hello class declared by the "Hello, World" program has a single member, the method
named Main . The Main method is declared with the static modifier. While instance methods
can reference a particular enclosing object instance using the keyword this , static methods
operate without reference to a particular object. By convention, a static method named Main
serves as the entry point of a program.
The output of the program is produced by the WriteLine method of the Console class in the
System namespace. This class is provided by the .NET Framework class libraries, which, by
default, are automatically referenced by the Microsoft C# compiler. Note that C# itself does not
have a separate runtime library. Instead, the .NET Framework is the runtime library of C#.
Program structure
The key organizational concepts in C# are programs , namespaces , types , members , and
assemblies . C# programs consist of one or more source files. Programs declare types, which
contain members and can be organized into namespaces. Classes and interfaces are examples
of types. Fields, methods, properties, and events are examples of members. When C# programs
are compiled, they are physically packaged into assemblies. Assemblies typically have the file
extension .exe or .dll , depending on whether they implement applications or libraries .
The example
using System;
namespace Acme.Collections
{
public class Stack
{
Entry top;
class Entry
{
public Entry next;
public object data;
declares a class named Stack in a namespace called Acme.Collections . The fully qualified
name of this class is Acme.Collections.Stack . The class contains several members: a field
named top , two methods named Push and Pop , and a nested class named Entry . The
Entry class further contains three members: a field named next , a field named data , and a
constructor. Assuming that the source code of the example is stored in the file acme.cs , the
command line
compiles the example as a library (code without a Main entry point) and produces an assembly
named acme.dll .
Assemblies contain executable code in the form of Intermediate Language (IL) instructions,
and symbolic information in the form of metadata . Before it is executed, the IL code in an
assembly is automatically converted to processor-specific code by the Just-In-Time (JIT)
compiler of .NET Common Language Runtime.
Because an assembly is a self-describing unit of functionality containing both code and
metadata, there is no need for #include directives and header files in C#. The public types and
members contained in a particular assembly are made available in a C# program simply by
referencing that assembly when compiling the program. For example, this program uses the
Acme.Collections.Stack class from the acme.dll assembly:
using System;
using Acme.Collections;
class Test
{
static void Main() {
Stack s = new Stack();
s.Push(1);
s.Push(10);
s.Push(100);
Console.WriteLine(s.Pop());
Console.WriteLine(s.Pop());
Console.WriteLine(s.Pop());
}
}
If the program is stored in the file test.cs , when test.cs is compiled, the acme.dll assembly
can be referenced using the compiler's /r option:
This creates an executable assembly named test.exe , which, when run, produces the output:
100
10
1
C# permits the source text of a program to be stored in several source files. When a multi-file
C# program is compiled, all of the source files are processed together, and the source files can
freely reference each other—conceptually, it is as if all the source files were concatenated into
one large file before being processed. Forward declarations are never needed in C# because,
with very few exceptions, declaration order is insignificant. C# does not limit a source file to
declaring only one public type nor does it require the name of the source file to match a type
declared in the source file.
C#'s value types are further divided into simple types , enum types , struct types , and
nullable types , and C#'s reference types are further divided into class types , interface
types , array types , and delegate types .
The following table provides an overview of C#'s type system.
High-precision decimal:
decimal
Boolean: bool
The eight integral types provide support for 8-bit, 16-bit, 32-bit, and 64-bit values in signed or
unsigned form.
The two floating point types, float and double , are represented using the 32-bit single-
precision and 64-bit double-precision IEEE 754 formats.
The decimal type is a 128-bit data type suitable for financial and monetary calculations.
C#'s bool type is used to represent boolean values—values that are either true or false .
Character and string processing in C# uses Unicode encoding. The char type represents a UTF-
16 code unit, and the string type represents a sequence of UTF-16 code units.
The following table summarizes C#'s numeric types.
16 short -32,768...32,767
32 int -
2,147,483,648...2,147,4
83,647
64 long -
9,223,372,036,854,775
,808...9,223,372,036,85
4,775,807
16 ushort 0...65,535
32 uint 0...4,294,967,295
64 ulong 0...18,446,744,073,709,
551,615
C# programs use type declarations to create new types. A type declaration specifies the name
and the members of the new type. Five of C#'s categories of types are user-definable: class
types, struct types, interface types, enum types, and delegate types.
A class type defines a data structure that contains data members (fields) and function members
(methods, properties, and others). Class types support single inheritance and polymorphism,
mechanisms whereby derived classes can extend and specialize base classes.
A struct type is similar to a class type in that it represents a structure with data members and
function members. However, unlike classes, structs are value types and do not require heap
allocation. Struct types do not support user-specified inheritance, and all struct types implicitly
inherit from type object .
An interface type defines a contract as a named set of public function members. A class or struct
that implements an interface must provide implementations of the interface's function
members. An interface may inherit from multiple base interfaces, and a class or struct may
implement multiple interfaces.
A delegate type represents references to methods with a particular parameter list and return
type. Delegates make it possible to treat methods as entities that can be assigned to variables
and passed as parameters. Delegates are similar to the concept of function pointers found in
some other languages, but unlike function pointers, delegates are object-oriented and type-safe.
Class, struct, interface and delegate types all support generics, whereby they can be
parameterized with other types.
An enum type is a distinct type with named constants. Every enum type has an underlying type,
which must be one of the eight integral types. The set of values of an enum type is the same as
the set of values of the underlying type.
C# supports single- and multi-dimensional arrays of any type. Unlike the types listed above,
array types do not have to be declared before they can be used. Instead, array types are
constructed by following a type name with square brackets. For example, int[] is a single-
dimensional array of int , int[,] is a two-dimensional array of int , and int[][] is a single-
dimensional array of single-dimensional arrays of int .
Nullable types also do not have to be declared before they can be used. For each non-nullable
value type T there is a corresponding nullable type T? , which can hold an additional value
null . For instance, int? is a type that can hold any 32 bit integer or the value null .
C#'s type system is unified such that a value of any type can be treated as an object. Every type
in C# directly or indirectly derives from the object class type, and object is the ultimate base
class of all types. Values of reference types are treated as objects simply by viewing the values
as type object . Values of value types are treated as objects by performing boxing and
unboxing operations. In the following example, an int value is converted to object and back
again to int .
using System;
class Test
{
static void Main() {
int i = 123;
object o = i; // Boxing
int j = (int)o; // Unboxing
}
}
When a value of a value type is converted to type object , an object instance, also called a
"box," is allocated to hold the value, and the value is copied into that box. Conversely, when an
object reference is cast to a value type, a check is made that the referenced object is a box of
the correct value type, and, if the check succeeds, the value in the box is copied out.
C#'s unified type system effectively means that value types can become objects "on demand."
Because of the unification, general-purpose libraries that use type object can be used with
both reference types and value types.
There are several kinds of variables in C#, including fields, array elements, local variables, and
parameters. Variables represent storage locations, and every variable has a type that
determines what values can be stored in the variable, as shown by the following table.
T Y P E O F VA RIA B L E P O SSIB L E C O N T EN T S
Expressions
Expressions are constructed from operands and operators . The operators of an expression
indicate which operations to apply to the operands. Examples of operators include + , - , * ,
/ , and new . Examples of operands include literals, fields, local variables, and expressions.
When an expression contains multiple operators, the precedence of the operators controls the
order in which the individual operators are evaluated. For example, the expression x + y * z is
evaluated as x + (y * z) because the * operator has higher precedence than the + operator.
Most operators can be overloaded . Operator overloading permits user-defined operator
implementations to be specified for operations where one or both of the operands are of a
user-defined class or struct type.
The following table summarizes C#'s operators, listing the operator categories in order of
precedence from highest to lowest. Operators in the same category have equal precedence.
x++ Post-increment
x-- Post-decrement
Unary +x Identity
-x Negation
!x Logical negation
~x Bitwise negation
++x Pre-increment
--x Pre-decrement
Multiplicative x * y Multiplication
x / y Division
x % y Remainder
x is T Return true if x is a T ,
false otherwise
x as T Return x typed as T , or
null if x is not a T
Equality x == y Equal
x != y Not equal
The try ... catch statement is used to catch exceptions that occur during execution of a block,
and the try ... finally statement is used to specify finalization code that is always executed,
whether an exception occurred or not.
The checked and unchecked statements are used to control the overflow checking context for
integral-type arithmetic operations and conversions.
The lock statement is used to obtain the mutual-exclusion lock for a given object, execute a
statement, and then release the lock.
The using statement is used to obtain a resource, execute a statement, and then dispose of that
resource.
Below are examples of each kind of statement
Local variable declarations
Expression statement
static void Main() {
int i;
i = 123; // Expression statement
Console.WriteLine(i); // Expression statement
i++; // Expression statement
Console.WriteLine(i); // Expression statement
}
if statement
switch statement
while statement
do statement
for statement
static void Main(string[] args) {
for (int i = 0; i < args.Length; i++) {
Console.WriteLine(args[i]);
}
}
foreach statement
break statement
continue statement
goto statement
return statement
yield statement
static IEnumerable<int> Range(int from, int to) {
for (int i = from; i < to; i++) {
yield return i;
}
yield break;
}
lock statement
class Account
{
decimal balance;
public void Withdraw(decimal amount) {
lock (this) {
if (amount > balance) {
throw new Exception("Insufficient funds");
}
balance -= amount;
}
}
}
using statement
Instances of classes are created using the new operator, which allocates memory for a new
instance, invokes a constructor to initialize the instance, and returns a reference to the instance.
The following statements create two Point objects and store references to those objects in two
variables:
M EM B ER DESC RIP T IO N
Accessibility
Each member of a class has an associated accessibility, which controls the regions of program
text that are able to access the member. There are five possible forms of accessibility. These are
summarized in the following table.
A C C ESSIB IL IT Y M EA N IN G
Type parameters
A class definition may specify a set of type parameters by following the class name with angle
brackets enclosing a list of type parameter names. The type parameters can the be used in the
body of the class declarations to define the members of the class. In the following example, the
type parameters of Pair are TFirst and TSecond :
A class type that is declared to take type parameters is called a generic class type. Struct,
interface and delegate types can also be generic.
When the generic class is used, type arguments must be provided for each of the type
parameters:
A generic type with type arguments provided, like Pair<int,string> above, is called a
constructed type.
Base classes
A class declaration may specify a base class by following the class name and type parameters
with a colon and the name of the base class. Omitting a base class specification is the same as
deriving from type object . In the following example, the base class of Point3D is Point , and
the base class of Point is object :
A class inherits the members of its base class. Inheritance means that a class implicitly contains
all members of its base class, except for the instance and static constructors, and the destructors
of the base class. A derived class can add new members to those it inherits, but it cannot
remove the definition of an inherited member. In the previous example, Point3D inherits the x
and y fields from Point , and every Point3D instance contains three fields, x , y , and z .
An implicit conversion exists from a class type to any of its base class types. Therefore, a
variable of a class type can reference an instance of that class or an instance of any derived
class. For example, given the previous class declarations, a variable of type Point can reference
either a Point or a Point3D :
Fields
A field is a variable that is associated with a class or with an instance of a class.
A field declared with the static modifier defines a static field . A static field identifies exactly
one storage location. No matter how many instances of a class are created, there is only ever
one copy of a static field.
A field declared without the static modifier defines an instance field . Every instance of a
class contains a separate copy of all the instance fields of that class.
In the following example, each instance of the Color class has a separate copy of the r , g ,
and b instance fields, but there is only one copy of the Black , White , Red , Green , and Blue
static fields:
As shown in the previous example, read-only fields may be declared with a readonly
modifier. Assignment to a readonly field can only occur as part of the field's declaration or in a
constructor in the same class.
Methods
A method is a member that implements a computation or action that can be performed by an
object or class. Static methods are accessed through the class. Instance methods are
accessed through instances of the class.
Methods have a (possibly empty) list of parameters , which represent values or variable
references passed to the method, and a return type , which specifies the type of the value
computed and returned by the method. A method's return type is void if it does not return a
value.
Like types, methods may also have a set of type parameters, for which type arguments must be
specified when the method is called. Unlike types, the type arguments can often be inferred
from the arguments of a method call and need not be explicitly given.
The signature of a method must be unique in the class in which the method is declared. The
signature of a method consists of the name of the method, the number of type parameters and
the number, modifiers, and types of its parameters. The signature of a method does not include
the return type.
Parameters
Parameters are used to pass values or variable references to methods. The parameters of a
method get their actual values from the arguments that are specified when the method is
invoked. There are four kinds of parameters: value parameters, reference parameters, output
parameters, and parameter arrays.
A value parameter is used for input parameter passing. A value parameter corresponds to a
local variable that gets its initial value from the argument that was passed for the parameter.
Modifications to a value parameter do not affect the argument that was passed for the
parameter.
Value parameters can be optional, by specifying a default value so that corresponding
arguments can be omitted.
A reference parameter is used for both input and output parameter passing. The argument
passed for a reference parameter must be a variable, and during execution of the method, the
reference parameter represents the same storage location as the argument variable. A
reference parameter is declared with the ref modifier. The following example shows the use of
ref parameters.
using System;
class Test
{
static void Swap(ref int x, ref int y) {
int temp = x;
x = y;
y = temp;
}
An output parameter is used for output parameter passing. An output parameter is similar to
a reference parameter except that the initial value of the caller-provided argument is
unimportant. An output parameter is declared with the out modifier. The following example
shows the use of out parameters.
using System;
class Test
{
static void Divide(int x, int y, out int result, out int remainder) {
result = x / y;
remainder = x % y;
}
Within a method that uses a parameter array, the parameter array behaves exactly like a regular
parameter of an array type. However, in an invocation of a method with a parameter array, it is
possible to pass either a single argument of the parameter array type or any number of
arguments of the element type of the parameter array. In the latter case, an array instance is
automatically created and initialized with the given arguments. This example
class Squares
{
static void Main() {
int i = 0;
int j;
while (i < 10) {
j = i * i;
Console.WriteLine("{0} x {0} = {1}", i, j);
i = i + 1;
}
}
}
C# requires a local variable to be definitely assigned before its value can be obtained. For
example, if the declaration of the previous i did not include an initial value, the compiler
would report an error for the subsequent usages of i because i would not be definitely
assigned at those points in the program.
A method can use return statements to return control to its caller. In a method returning void
, return statements cannot specify an expression. In a method returning non- void , return
statements must include an expression that computes the return value.
Static and instance methods
A method declared with a static modifier is a static method . A static method does not
operate on a specific instance and can only directly access static members.
A method declared without a static modifier is an instance method . An instance method
operates on a specific instance and can access both static and instance members. The instance
on which an instance method was invoked can be explicitly accessed as this . It is an error to
refer to this in a static method.
The following Entity class has both static and instance members.
class Entity
{
static int nextSerialNo;
int serialNo;
public Entity() {
serialNo = nextSerialNo++;
}
Each Entity instance contains a serial number (and presumably some other information that is
not shown here). The Entity constructor (which is like an instance method) initializes the new
instance with the next available serial number. Because the constructor is an instance member, it
is permitted to access both the serialNo instance field and the nextSerialNo static field.
The GetNextSerialNo and SetNextSerialNo static methods can access the nextSerialNo static
field, but it would be an error for them to directly access the serialNo instance field.
The following example shows the use of the Entity class.
using System;
class Test
{
static void Main() {
Entity.SetNextSerialNo(1000);
Entity e1 = new Entity();
Entity e2 = new Entity();
Console.WriteLine(e1.GetSerialNo()); // Outputs "1000"
Console.WriteLine(e2.GetSerialNo()); // Outputs "1001"
Console.WriteLine(Entity.GetNextSerialNo()); // Outputs "1002"
}
}
Note that the SetNextSerialNo and GetNextSerialNo static methods are invoked on the class
whereas the GetSerialNo instance method is invoked on instances of the class.
Virtual, override, and abstract methods
When an instance method declaration includes a virtual modifier, the method is said to be a
vir tual method . When no virtual modifier is present, the method is said to be a non-
vir tual method .
When a virtual method is invoked, the run-time type of the instance for which that invocation
takes place determines the actual method implementation to invoke. In a nonvirtual method
invocation, the compile-time type of the instance is the determining factor.
A virtual method can be overridden in a derived class. When an instance method declaration
includes an override modifier, the method overrides an inherited virtual method with the
same signature. Whereas a virtual method declaration introduces a new method, an override
method declaration specializes an existing inherited virtual method by providing a new
implementation of that method.
An abstract method is a virtual method with no implementation. An abstract method is
declared with the abstract modifier and is permitted only in a class that is also declared
abstract . An abstract method must be overridden in every non-abstract derived class.
The following example declares an abstract class, Expression , which represents an expression
tree node, and three derived classes, Constant , VariableReference , and Operation , which
implement expression tree nodes for constants, variable references, and arithmetic operations.
(This is similar to, but not to be confused with the expression tree types introduced in
Expression tree types).
using System;
using System.Collections;
The previous four classes can be used to model arithmetic expressions. For example, using
instances of these classes, the expression x + 3 can be represented as follows.
Expression e = new Operation(
new VariableReference("x"),
'+',
new Constant(3));
The Evaluate method of an Expression instance is invoked to evaluate the given expression
and produce a double value. The method takes as an argument a Hashtable that contains
variable names (as keys of the entries) and values (as values of the entries). The Evaluate
method is a virtual abstract method, meaning that non-abstract derived classes must override it
to provide an actual implementation.
A Constant's implementation of Evaluate simply returns the stored constant. A
VariableReference 's implementation looks up the variable name in the hashtable and returns
the resulting value. An Operation 's implementation first evaluates the left and right operands
(by recursively invoking their Evaluate methods) and then performs the given arithmetic
operation.
The following program uses the Expression classes to evaluate the expression x * (y + 2) for
different values of x and y .
using System;
using System.Collections;
class Test
{
static void Main() {
Expression e = new Operation(
new VariableReference("x"),
'*',
new Operation(
new VariableReference("y"),
'+',
new Constant(2)
)
);
Hashtable vars = new Hashtable();
vars["x"] = 3;
vars["y"] = 5;
Console.WriteLine(e.Evaluate(vars)); // Outputs "21"
vars["x"] = 1.5;
vars["y"] = 9;
Console.WriteLine(e.Evaluate(vars)); // Outputs "16.5"
}
}
Method overloading
Method overloading permits multiple methods in the same class to have the same name as
long as they have unique signatures. When compiling an invocation of an overloaded method,
the compiler uses overload resolution to determine the specific method to invoke. Overload
resolution finds the one method that best matches the arguments or reports an error if no
single best match can be found. The following example shows overload resolution in effect. The
comment for each invocation in the Main method shows which method is actually invoked.
class Test
{
static void F() {
Console.WriteLine("F()");
}
As shown by the example, a particular method can always be selected by explicitly casting the
arguments to the exact parameter types and/or explicitly supplying type arguments.
Other function members
Members that contain executable code are collectively known as the function members of a
class. The preceding section describes methods, which are the primary kind of function
members. This section describes the other kinds of function members supported by C#:
constructors, properties, indexers, events, operators, and destructors.
The following code shows a generic class called List<T> , which implements a growable list of
objects. The class contains several examples of the most common kinds of function members.
// Fields...
T[] items;
int count;
// Constructors...
public List(int capacity = defaultCapacity) {
items = new T[capacity];
}
// Properties...
// Properties...
public int Count {
get { return count; }
}
public int Capacity {
get {
return items.Length;
}
set {
if (value < count) value = count;
if (value != items.Length) {
T[] newItems = new T[value];
Array.Copy(items, 0, newItems, 0, count);
items = newItems;
}
}
}
// Indexer...
public T this[int index] {
get {
return items[index];
}
set {
items[index] = value;
OnChanged();
}
}
// Methods...
public void Add(T item) {
if (count == Capacity) Capacity = count * 2;
items[count] = item;
count++;
OnChanged();
}
protected virtual void OnChanged() {
if (Changed != null) Changed(this, EventArgs.Empty);
}
public override bool Equals(object other) {
return Equals(this, other as List<T>);
}
static bool Equals(List<T> a, List<T> b) {
if (a == null) return b == null;
if (b == null || a.count != b.count) return false;
for (int i = 0; i < a.count; i++) {
if (!object.Equals(a.items[i], b.items[i])) {
return false;
}
}
return true;
}
// Event...
public event EventHandler Changed;
// Operators...
public static bool operator ==(List<T> a, List<T> b) {
return Equals(a, b);
}
public static bool operator !=(List<T> a, List<T> b) {
return !Equals(a, b);
}
}
Constructors
C# supports both instance and static constructors. An instance constructor is a member that
implements the actions required to initialize an instance of a class. A static constructor is a
member that implements the actions required to initialize a class itself when it is first loaded.
A constructor is declared like a method with no return type and the same name as the
containing class. If a constructor declaration includes a static modifier, it declares a static
constructor. Otherwise, it declares an instance constructor.
Instance constructors can be overloaded. For example, the List<T> class declares two instance
constructors, one with no parameters and one that takes an int parameter. Instance
constructors are invoked using the new operator. The following statements allocate two
List<string> instances using each of the constructors of the List class.
Unlike other members, instance constructors are not inherited, and a class has no instance
constructors other than those actually declared in the class. If no instance constructor is
supplied for a class, then an empty one with no parameters is automatically provided.
Properties
Proper ties are a natural extension of fields. Both are named members with associated types,
and the syntax for accessing fields and properties is the same. However, unlike fields, properties
do not denote storage locations. Instead, properties have accessors that specify the statements
to be executed when their values are read or written.
A property is declared like a field, except that the declaration ends with a get accessor and/or
a set accessor written between the delimiters { and } instead of ending in a semicolon. A
property that has both a get accessor and a set accessor is a read-write proper ty , a
property that has only a get accessor is a read-only proper ty , and a property that has only
a set accessor is a write-only proper ty .
A get accessor corresponds to a parameterless method with a return value of the property
type. Except as the target of an assignment, when a property is referenced in an expression, the
get accessor of the property is invoked to compute the value of the property.
A set accessor corresponds to a method with a single parameter named value and no return
type. When a property is referenced as the target of an assignment or as the operand of ++ or
-- , the set accessor is invoked with an argument that provides the new value.
The List<T> class declares two properties, Count and Capacity , which are read-only and
read-write, respectively. The following is an example of use of these properties.
Similar to fields and methods, C# supports both instance properties and static properties. Static
properties are declared with the static modifier, and instance properties are declared without
it.
The accessor(s) of a property can be virtual. When a property declaration includes a virtual ,
abstract , or override modifier, it applies to the accessor(s) of the property.
Indexers
An indexer is a member that enables objects to be indexed in the same way as an array. An
indexer is declared like a property except that the name of the member is this followed by a
parameter list written between the delimiters [ and ] . The parameters are available in the
accessor(s) of the indexer. Similar to properties, indexers can be read-write, read-only, and
write-only, and the accessor(s) of an indexer can be virtual.
The List class declares a single read-write indexer that takes an int parameter. The indexer
makes it possible to index List instances with int values. For example
Indexers can be overloaded, meaning that a class can declare multiple indexers as long as the
number or types of their parameters differ.
Events
An event is a member that enables a class or object to provide notifications. An event is
declared like a field except that the declaration includes an event keyword and the type must
be a delegate type.
Within a class that declares an event member, the event behaves just like a field of a delegate
type (provided the event is not abstract and does not declare accessors). The field stores a
reference to a delegate that represents the event handlers that have been added to the event. If
no event handles are present, the field is null .
The List<T> class declares a single event member called Changed , which indicates that a new
item has been added to the list. The Changed event is raised by the OnChanged virtual method,
which first checks whether the event is null (meaning that no handlers are present). The
notion of raising an event is precisely equivalent to invoking the delegate represented by the
event—thus, there are no special language constructs for raising events.
Clients react to events through event handlers . Event handlers are attached using the +=
operator and removed using the -= operator. The following example attaches an event handler
to the Changed event of a List<string> .
using System;
class Test
{
static int changeCount;
For advanced scenarios where control of the underlying storage of an event is desired, an event
declaration can explicitly provide add and remove accessors, which are somewhat similar to
the set accessor of a property.
Operators
An operator is a member that defines the meaning of applying a particular expression
operator to instances of a class. Three kinds of operators can be defined: unary operators,
binary operators, and conversion operators. All operators must be declared as public and
static .
The List<T> class declares two operators, operator== and operator!= , and thus gives new
meaning to expressions that apply those operators to List instances. Specifically, the
operators define equality of two List<T> instances as comparing each of the contained objects
using their Equals methods. The following example uses the == operator to compare two
List<int> instances.
using System;
class Test
{
static void Main() {
List<int> a = new List<int>();
a.Add(1);
a.Add(2);
List<int> b = new List<int>();
b.Add(1);
b.Add(2);
Console.WriteLine(a == b); // Outputs "True"
b.Add(3);
Console.WriteLine(a == b); // Outputs "False"
}
}
The first Console.WriteLine outputs True because the two lists contain the same number of
objects with the same values in the same order. Had List<T> not defined operator== , the first
Console.WriteLine would have output False because a and b reference different
List<int> instances.
Destructors
A destructor is a member that implements the actions required to destruct an instance of a
class. Destructors cannot have parameters, they cannot have accessibility modifiers, and they
cannot be invoked explicitly. The destructor for an instance is invoked automatically during
garbage collection.
The garbage collector is allowed wide latitude in deciding when to collect objects and run
destructors. Specifically, the timing of destructor invocations is not deterministic, and
destructors may be executed on any thread. For these and other reasons, classes should
implement destructors only when no other solutions are feasible.
The using statement provides a better approach to object destruction.
Structs
Like classes, structs are data structures that can contain data members and function members,
but unlike classes, structs are value types and do not require heap allocation. A variable of a
struct type directly stores the data of the struct, whereas a variable of a class type stores a
reference to a dynamically allocated object. Struct types do not support user-specified
inheritance, and all struct types implicitly inherit from type object .
Structs are particularly useful for small data structures that have value semantics. Complex
numbers, points in a coordinate system, or key-value pairs in a dictionary are all good examples
of structs. The use of structs rather than classes for small data structures can make a large
difference in the number of memory allocations an application performs. For example, the
following program creates and initializes an array of 100 points. With Point implemented as a
class, 101 separate objects are instantiated—one for the array and one each for the 100
elements.
class Point
{
public int x, y;
class Test
{
static void Main() {
Point[] points = new Point[100];
for (int i = 0; i < 100; i++) points[i] = new Point(i, i);
}
}
struct Point
{
public int x, y;
Now, only one object is instantiated—the one for the array—and the Point instances are
stored in-line in the array.
Struct constructors are invoked with the new operator, but that does not imply that memory is
being allocated. Instead of dynamically allocating an object and returning a reference to it, a
struct constructor simply returns the struct value itself (typically in a temporary location on the
stack), and this value is then copied as necessary.
With classes, it is possible for two variables to reference the same object and thus possible for
operations on one variable to affect the object referenced by the other variable. With structs, the
variables each have their own copy of the data, and it is not possible for operations on one to
affect the other. For example, the output produced by the following code fragment depends on
whether Point is a class or a struct.
If Point is a class, the output is 20 because a and b reference the same object. If Point is a
struct, the output is 10 because the assignment of a to b creates a copy of the value, and
this copy is unaffected by the subsequent assignment to a.x .
The previous example highlights two of the limitations of structs. First, copying an entire struct
is typically less efficient than copying an object reference, so assignment and value parameter
passing can be more expensive with structs than with reference types. Second, except for ref
and out parameters, it is not possible to create references to structs, which rules out their
usage in a number of situations.
Arrays
An array is a data structure that contains a number of variables that are accessed through
computed indices. The variables contained in an array, also called the elements of the array, are
all of the same type, and this type is called the element type of the array.
Array types are reference types, and the declaration of an array variable simply sets aside space
for a reference to an array instance. Actual array instances are created dynamically at run-time
using the new operator. The new operation specifies the length of the new array instance,
which is then fixed for the lifetime of the instance. The indices of the elements of an array range
from 0 to Length - 1 . The new operator automatically initializes the elements of an array to
their default value, which, for example, is zero for all numeric types and null for all reference
types.
The following example creates an array of int elements, initializes the array, and prints out the
contents of the array.
using System;
class Test
{
static void Main() {
int[] a = new int[10];
for (int i = 0; i < a.Length; i++) {
a[i] = i * i;
}
for (int i = 0; i < a.Length; i++) {
Console.WriteLine("a[{0}] = {1}", i, a[i]);
}
}
}
This example creates and operates on a single-dimensional array . C# also supports multi-
dimensional arrays . The number of dimensions of an array type, also known as the rank of
the array type, is one plus the number of commas written between the square brackets of the
array type. The following example allocates a one-dimensional, a two-dimensional, and a three-
dimensional array.
The a1 array contains 10 elements, the a2 array contains 50 (10 × 5) elements, and the a3
array contains 100 (10 × 5 × 2) elements.
The element type of an array can be any type, including an array type. An array with elements of
an array type is sometimes called a jagged array because the lengths of the element arrays do
not all have to be the same. The following example allocates an array of arrays of int :
The first line creates an array with three elements, each of type int[] and each with an initial
value of null . The subsequent lines then initialize the three elements with references to
individual array instances of varying lengths.
The new operator permits the initial values of the array elements to be specified using an
array initializer , which is a list of expressions written between the delimiters { and } . The
following example allocates and initializes an int[] with three elements.
Note that the length of the array is inferred from the number of expressions between { and
} . Local variable and field declarations can be shortened further such that the array type does
not have to be restated.
Interfaces
An interface defines a contract that can be implemented by classes and structs. An interface
can contain methods, properties, events, and indexers. An interface does not provide
implementations of the members it defines—it merely specifies the members that must be
supplied by classes or structs that implement the interface.
Interfaces may employ multiple inheritance . In the following example, the interface
IComboBox inherits from both ITextBox and IListBox .
interface IControl
{
void Paint();
}
Classes and structs can implement multiple interfaces. In the following example, the class
EditBox implements both IControl and IDataBound .
interface IDataBound
{
void Bind(Binder b);
}
When a class or struct implements a particular interface, instances of that class or struct can be
implicitly converted to that interface type. For example
In cases where an instance is not statically known to implement a particular interface, dynamic
type casts can be used. For example, the following statements use dynamic type casts to obtain
an object's IControl and IDataBound interface implementations. Because the actual type of the
object is EditBox , the casts succeed.
In the previous EditBox class, the Paint method from the IControl interface and the Bind
method from the IDataBound interface are implemented using public members. C# also
supports explicit interface member implementations , using which the class or struct can
avoid making the members public . An explicit interface member implementation is written
using the fully qualified interface member name. For example, the EditBox class could
implement the IControl.Paint and IDataBound.Bind methods using explicit interface member
implementations as follows.
Explicit interface members can only be accessed via the interface type. For example, the
implementation of IControl.Paint provided by the previous EditBox class can only be
invoked by first converting the EditBox reference to the IControl interface type.
Enums
An enum type is a distinct value type with a set of named constants. The following example
declares and uses an enum type named Color with three constant values, Red , Green , and
Blue .
using System;
enum Color
{
Red,
Green,
Blue
}
class Test
{
static void PrintColor(Color color) {
switch (color) {
case Color.Red:
Console.WriteLine("Red");
break;
case Color.Green:
Console.WriteLine("Green");
break;
case Color.Blue:
Console.WriteLine("Blue");
break;
default:
Console.WriteLine("Unknown color");
break;
}
}
Each enum type has a corresponding integral type called the underlying type of the enum
type. An enum type that does not explicitly declare an underlying type has an underlying type of
int . An enum type's storage format and range of possible values are determined by its
underlying type. The set of values that an enum type can take on is not limited by its enum
members. In particular, any value of the underlying type of an enum can be cast to the enum
type and is a distinct valid value of that enum type.
The following example declares an enum type named Alignment with an underlying type of
sbyte .
As shown by the previous example, an enum member declaration can include a constant
expression that specifies the value of the member. The constant value for each enum member
must be in the range of the underlying type of the enum. When an enum member declaration
does not explicitly specify a value, the member is given the value zero (if it is the first member
in the enum type) or the value of the textually preceding enum member plus one.
Enum values can be converted to integral values and vice versa using type casts. For example
int i = (int)Color.Blue; // int i = 2;
Color c = (Color)2; // Color c = Color.Blue;
The default value of any enum type is the integral value zero converted to the enum type. In
cases where variables are automatically initialized to a default value, this is the value given to
variables of enum types. In order for the default value of an enum type to be easily available,
the literal 0 implicitly converts to any enum type. Thus, the following is permitted.
Color c = 0;
Delegates
A delegate type represents references to methods with a particular parameter list and return
type. Delegates make it possible to treat methods as entities that can be assigned to variables
and passed as parameters. Delegates are similar to the concept of function pointers found in
some other languages, but unlike function pointers, delegates are object-oriented and type-safe.
The following example declares and uses a delegate type named Function .
using System;
class Multiplier
{
double factor;
class Test
{
static double Square(double x) {
return x * x;
}
An instance of the Function delegate type can reference any method that takes a double
argument and returns a double value. The Apply method applies a given Function to the
elements of a double[] , returning a double[] with the results. In the Main method, Apply is
used to apply three different functions to a double[] .
A delegate can reference either a static method (such as Square or Math.Sin in the previous
example) or an instance method (such as m.Multiply in the previous example). A delegate that
references an instance method also references a particular object, and when the instance
method is invoked through the delegate, that object becomes this in the invocation.
Delegates can also be created using anonymous functions, which are "inline methods" that are
created on the fly. Anonymous functions can see the local variables of the surrounding
methods. Thus, the multiplier example above can be written more easily without using a
Multiplier class:
An interesting and useful property of a delegate is that it does not know or care about the class
of the method it references; all that matters is that the referenced method has the same
parameters and return type as the delegate.
Attributes
Types, members, and other entities in a C# program support modifiers that control certain
aspects of their behavior. For example, the accessibility of a method is controlled using the
public , protected , internal , and private modifiers. C# generalizes this capability such that
user-defined types of declarative information can be attached to program entities and retrieved
at run-time. Programs specify this additional declarative information by defining and using
attributes .
The following example declares a HelpAttribute attribute that can be placed on program
entities to provide links to their associated documentation.
using System;
All attribute classes derive from the System.Attribute base class provided by the .NET
Framework. Attributes can be applied by giving their name, along with any arguments, inside
square brackets just before the associated declaration. If an attribute's name ends in Attribute ,
that part of the name can be omitted when the attribute is referenced. For example, the
HelpAttribute attribute can be used as follows.
[Help("http://msdn.microsoft.com/.../MyClass.htm")]
public class Widget
{
[Help("http://msdn.microsoft.com/.../MyClass.htm", Topic = "Display")]
public void Display(string text) {}
}
This example attaches a HelpAttribute to the Widget class and another HelpAttribute to the
Display method in the class. The public constructors of an attribute class control the
information that must be provided when the attribute is attached to a program entity.
Additional information can be provided by referencing public read-write properties of the
attribute class (such as the reference to the Topic property previously).
The following example shows how attribute information for a given program entity can be
retrieved at run-time using reflection.
using System;
using System.Reflection;
class Test
{
static void ShowHelp(MemberInfo member) {
HelpAttribute a = Attribute.GetCustomAttribute(member,
typeof(HelpAttribute)) as HelpAttribute;
if (a == null) {
Console.WriteLine("No help for {0}", member);
}
else {
Console.WriteLine("Help for {0}:", member);
Console.WriteLine(" Url={0}, Topic={1}", a.Url, a.Topic);
}
}
When a particular attribute is requested through reflection, the constructor for the attribute
class is invoked with the information provided in the program source, and the resulting
attribute instance is returned. If additional information was provided through properties, those
properties are set to the given values before the attribute instance is returned.
Pattern Matching for C# 7
9/3/2020 • 15 minutes to read • Edit Online
Pattern matching extensions for C# enable many of the benefits of algebraic data types and pattern matching from
functional languages, but in a way that smoothly integrates with the feel of the underlying language. The basic
features are: record types, which are types whose semantic meaning is described by the shape of the data; and
pattern matching, which is a new expression form that enables extremely concise multilevel decomposition of
these data types. Elements of this approach are inspired by related features in the programming languages F# and
Scala.
Is expression
The is operator is extended to test an expression against a pattern.
relational_expression
: relational_expression 'is' pattern
;
This form of relational_expression is in addition to the existing forms in the C# specification. It is a compile-time
error if the relational_expression to the left of the is token does not designate a value or does not have a type.
Every identifier of the pattern introduces a new local variable that is definitely assigned after the is operator is
true (i.e. definitely assigned when true).
Note: There is technically an ambiguity between type in an is-expression and constant_pattern, either of
which might be a valid parse of a qualified identifier. We try to bind it as a type for compatibility with previous
versions of the language; only if that fails do we resolve it as we do in other contexts, to the first thing found
(which must be either a constant or a type). This ambiguity is only present on the right-hand-side of an is
expression.
Patterns
Patterns are used in the is operator and in a switch_statement to express the shape of data against which
incoming data is to be compared. Patterns may be recursive so that parts of the data may be matched against sub-
patterns.
pattern
: declaration_pattern
| constant_pattern
| var_pattern
;
declaration_pattern
: type simple_designation
;
constant_pattern
: shift_expression
;
var_pattern
: 'var' simple_designation
;
Note: There is technically an ambiguity between type in an is-expression and constant_pattern, either of
which might be a valid parse of a qualified identifier. We try to bind it as a type for compatibility with previous
versions of the language; only if that fails do we resolve it as we do in other contexts, to the first thing found
(which must be either a constant or a type). This ambiguity is only present on the right-hand-side of an is
expression.
Declaration pattern
The declaration_pattern both tests that an expression is of a given type and casts it to that type if the test succeeds.
If the simple_designation is an identifier, it introduces a local variable of the given type named by the given
identifier. That local variable is definitely assigned when the result of the pattern-matching operation is true.
declaration_pattern
: type simple_designation
;
The runtime semantic of this expression is that it tests the runtime type of the left-hand relational_expression
operand against the type in the pattern. If it is of that runtime type (or some subtype), the result of the
is operator is true . It declares a new local variable named by the identifier that is assigned the value of the left-
hand operand when the result is true .
Certain combinations of static type of the left-hand-side and the given type are considered incompatible and result
in compile-time error. A value of static type E is said to be pattern compatible with the type T if there exists an
identity conversion, an implicit reference conversion, a boxing conversion, an explicit reference conversion, or an
unboxing conversion from E to T . It is a compile-time error if an expression of type E is not pattern compatible
with the type in a type pattern that it is matched with.
Note: In C# 7.1 we extend this to permit a pattern-matching operation if either the input type or the type T is
an open type. This paragraph is replaced by the following:
Certain combinations of static type of the left-hand-side and the given type are considered incompatible and
result in compile-time error. A value of static type E is said to be pattern compatible with the type T if there
exists an identity conversion, an implicit reference conversion, a boxing conversion, an explicit reference
conversion, or an unboxing conversion from E to T , or if either E or T is an open type . It is a compile-
time error if an expression of type E is not pattern compatible with the type in a type pattern that it is
matched with.
The declaration pattern is useful for performing run-time type tests of reference types, and replaces the idiom
var v = expr as Type;
if (v != null) { // code using v }
int? x = 3;
if (x is int v) { // code using v }
The condition of the if statement is true at runtime and the variable v holds the value 3 of type int inside
the block.
Constant pattern
constant_pattern
: shift_expression
;
A constant pattern tests the value of an expression against a constant value. The constant may be any constant
expression, such as a literal, the name of a declared const variable, or an enumeration constant, or a typeof
expression.
If both e and c are of integral types, the pattern is considered matched if the result of the expression e == c is
true .
Otherwise the pattern is considered matching if object.Equals(e, c) returns true . In this case it is a compile-
time error if the static type of e is not pattern compatible with the type of the constant.
Var pattern
var_pattern
: 'var' simple_designation
;
An expression e matches a var_pattern always. In other words, a match to a var pattern always succeeds. If the
simple_designation is an identifier, then at runtime the value of e is bound to a newly introduced local variable. The
type of the local variable is the static type of e.
It is an error if the name var binds to a type.
Switch statement
The switch statement is extended to select for execution the first block having an associated pattern that matches
the switch expression.
switch_label
: 'case' complex_pattern case_guard? ':'
| 'case' constant_expression case_guard? ':'
| 'default' ':'
;
case_guard
: 'when' expression
;
The order in which patterns are matched is not defined. A compiler is permitted to match patterns out of order, and
to reuse the results of already matched patterns to compute the result of matching of other patterns.
If a case-guard is present, its expression is of type bool . It is evaluated as an additional condition that must be
satisfied for the case to be considered satisfied.
It is an error if a switch_label can have no effect at runtime because its pattern is subsumed by previous cases.
[TODO: We should be more precise about the techniques the compiler is required to use to reach this judgment.]
A pattern variable declared in a switch_label is definitely assigned in its case block if and only if that case block
contains precisely one switch_label.
[TODO: We should specify when a switch block is reachable.]
Scope of pattern variables
The scope of a variable declared in a pattern is as follows:
If the pattern is a case label, then the scope of the variable is the case block.
Otherwise the variable is declared in an is_pattern expression, and its scope is based on the construct immediately
enclosing the expression containing the is_pattern expression as follows:
If the expression is in an expression-bodied lambda, its scope is the body of the lambda.
If the expression is in an expression-bodied method or property, its scope is the body of the method or
property.
If the expression is in a when clause of a catch clause, its scope is that catch clause.
If the expression is in an iteration_statement, its scope is just that statement.
Otherwise if the expression is in some other statement form, its scope is the scope containing the statement.
For the purpose of determining the scope, an embedded_statement is considered to be in its own scope. For
example, the grammar for an if_statement is
if_statement
: 'if' '(' boolean_expression ')' embedded_statement
| 'if' '(' boolean_expression ')' embedded_statement 'else' embedded_statement
;
So if the controlled statement of an if_statement declares a pattern variable, its scope is restricted to that
embedded_statement:
In this case the scope of z is the embedded statement M(y is var z); .
Other cases are errors for other reasons (e.g. in a parameter's default value or an attribute, both of which are an
error because those contexts require a constant expression).
In C# 7.3 we added the following contexts in which a pattern variable may be declared:
If the expression is in a constructor initializer, its scope is the constructor initializer and the constructor's
body.
If the expression is in a field initializer, its scope is the equals_value_clause in which it appears.
If the expression is in a query clause that is specified to be translated into the body of a lambda, its scope is
just that expression.
F(G<A,B>(7));
could be interpreted as a call to F with two arguments, G < A and B > (7) . Alternatively, it could be
interpreted as a call to F with one argument, which is a call to a generic method G with two type arguments
and one regular argument.
If a sequence of tokens can be parsed (in context) as a simple-name (§7.6.3), member-access (§7.6.5), or
pointer-member-access (§18.5.2) ending with a type-argument-list (§4.4.1), the token immediately following
the closing > token is examined. If it is one of
( ) ] } : ; , . ? == != | ^
F(G<A,B>(7));
will, according to this rule, be interpreted as a call to F with one argument, which is a call to a generic method
G with two type arguments and one regular argument. The statements
will be interpreted as a less than operator, greater than operator, and unary plus operator, as if the statement
had been written x = (F < A) > (+y) , instead of as a simple-name with a type-argument-list followed by a
binary plus operator. In the statement
x = y is C<T> + z;
There are a number of changes being introduced in C# 7 that make these disambiguation rules no longer sufficient
to handle the complexity of the language.
Out variable declarations
It is now possible to declare a variable in an out argument:
Since the language grammar for the argument uses expression, this context is subject to the disambiguation rule.
In this case the closing > is followed by an identifier, which is not one of the tokens that permits it to be treated as
a type-argument-list. I therefore propose to add identifier to the set of tokens that triggers the
disambiguation to a type-argument-list .
Tuples and deconstruction declarations
A tuple literal runs into exactly the same issue. Consider the tuple expression
Under the old C# 6 rules for parsing an argument list, this would parse as a tuple with four elements, starting with
A < B as the first. However, when this appears on the left of a deconstruction, we want the disambiguation
triggered by the identifier token as described above:
(A<B,C> D, E<F,G> H) = e;
This is a deconstruction declaration which declares two variables, the first of which is of type A<B,C> and named
D . In other words, the tuple literal contains two expressions, each of which is a declaration expression.
For simplicity of the specification and compiler, I propose that this tuple literal be parsed as a two-element tuple
wherever it appears (whether or not it appears on the left-hand-side of an assignment). That would be a natural
result of the disambiguation described in the previous section.
Pattern-matching
Pattern matching introduces a new context where the expression-type ambiguity arises. Previously the right-hand-
side of an is operator was a type. Now it can be a type or expression, and if it is a type it may be followed by an
identifier. This can, technically, change the meaning of existing code:
var x = e is T<A> B;
which declares a variable B of type T<A> . Fortunately, the native and Roslyn compilers have a bug whereby they
give a syntax error on the C#6 code. Therefore this particular breaking change is not a concern.
Pattern-matching introduces additional tokens that should drive the ambiguity resolution toward selecting a type.
The following examples of existing valid C#6 code would be broken without additional disambiguation rules:
( ) ] } : ; , . ? == != | ^
to
( ) ] } : ; , . ? == != | ^ && || & [
And, in certain contexts, we treat identifier as a disambiguating token. Those contexts are where the sequence of
tokens being disambiguated is immediately preceded by one of the keywords is , case , or out , or arises while
parsing the first element of a tuple literal (in which case the tokens are preceded by ( or : and the identifier is
followed by a , ) or a subsequent element of a tuple literal.
Modified disambiguation rule
The revised disambiguation rule would be something like this
If a sequence of tokens can be parsed (in context) as a simple-name (§7.6.3), member-access (§7.6.5), or
pointer-member-access (§18.5.2) ending with a type-argument-list (§4.4.1), the token immediately following
the closing > token is examined, to see if it is
One of ( ) ] } : ; , . ? == != | ^ && || & [ ; or
One of the relational operators < > <= >= is as ; or
A contextual query keyword appearing inside a query expression; or
In certain contexts, we treat identifier as a disambiguating token. Those contexts are where the sequence of
tokens being disambiguated is immediately preceded by one of the keywords is , case or out , or arises
while parsing the first element of a tuple literal (in which case the tokens are preceded by ( or : and the
identifier is followed by a , ) or a subsequent element of a tuple literal.
If the following token is among this list, or an identifier in such a context, then the type-argument-list is
retained as part of the simple-name, member-access or pointer-member-access and any other possible parse
of the sequence of tokens is discarded. Otherwise, the type-argument-list is not considered to be part of the
simple-name, member-access or pointer-member-access, even if there is no other possible parse of the
sequence of tokens. Note that these rules are not applied when parsing a type-argument-list in a namespace-
or-type-name (§3.8).
Breaking changes due to this proposal
No breaking changes are known due to this proposed disambiguation rule.
Interesting examples
Here are some interesting results of these disambiguation rules:
The expression (A < B, C > D) is a tuple with two elements, each a comparison.
The expression (A<B,C> D, E) is a tuple with two elements, the first of which is a declaration expression.
The invocation M(A < B, C > D, E) has three arguments.
The invocation M(out A<B,C> D, E) has two arguments, the first of which is an out declaration.
The expression e is A<B> C uses a declaration expression.
The case label case A<B> C: uses a declaration expression.
if (expr is Type v) {
// code using v
}
Testing nullable
We can replace the idiom
Type? v = x?.y?.z;
if (v.HasValue) {
var value = v.GetValueOrDefault();
// code using value
}
Arithmetic simplification
Suppose we define a set of recursive types to represent expressions (per a separate proposal):
abstract class Expr;
class X() : Expr;
class Const(double Value) : Expr;
class Add(Expr Left, Expr Right) : Expr;
class Mult(Expr Left, Expr Right) : Expr;
class Neg(Expr Value) : Expr;
Expr Deriv(Expr e)
{
switch (e) {
case X(): return Const(1);
case Const(*): return Const(0);
case Add(var Left, var Right):
return Add(Deriv(Left), Deriv(Right));
case Mult(var Left, var Right):
return Add(Mult(Deriv(Left), Right), Mult(Left, Deriv(Right)));
case Neg(var Value):
return Neg(Deriv(Value));
}
}
Expr Simplify(Expr e)
{
switch (e) {
case Mult(Const(0), *): return Const(0);
case Mult(*, Const(0)): return Const(0);
case Mult(Const(1), var x): return Simplify(x);
case Mult(var x, Const(1)): return Simplify(x);
case Mult(Const(var l), Const(var r)): return Const(l*r);
case Add(Const(0), var x): return Simplify(x);
case Add(var x, Const(0)): return Simplify(x);
case Add(Const(var l), Const(var r)): return Const(l+r);
case Neg(Const(var k)): return Const(-k);
default: return e;
}
}
C# walkthroughs
9/3/2020 • 2 minutes to read • Edit Online
Walkthroughs give step-by-step instructions for common scenarios, which makes them a good place to start
learning about the product or a particular feature area.
This section contains links to C# programming walkthroughs.
In this section
Process asynchronous tasks as they complete
Shows how to create an asynchronous solution by using async and await.
Creating a Windows Runtime Component in C# or Visual Basic and Calling it from JavaScript
Shows how to create a Windows Runtime type, package it in a Windows Runtime component, and then call
the component from a Windows 8.x Store app that's built for Windows by using JavaScript.
Office Programming (C# and Visual Basic)
Shows how to create an Excel workbook and a Word document by using C# and Visual Basic.
Creating and Using Dynamic Objects (C# and Visual Basic)
Shows how to create a custom object that dynamically exposes the contents of a text file, and how to create
a project that uses the IronPython library.
Authoring a Composite Control with Visual C#
Demonstrates creating a simple composite control and extending its functionality through inheritance.
Creating a Windows Forms Control that Takes Advantage of Visual Studio Design-Time Features
Illustrates how to create a custom designer for a custom control.
Inheriting from a Windows Forms Control with Visual C#
Demonstrates creating a simple inherited button control. This button inherits functionality from the standard
Windows Forms button and exposes a custom member.
Debugging Custom Windows Forms Controls at Design Time
Describes how to debug the design-time behavior of your custom control.
Walkthrough: Perform common tasks using designer actions
Demonstrates some of the commonly performed tasks such as adding or removing a tab on a TabControl ,
docking a control to its parent, and changing the orientation of a SplitContainer control.
Writing Queries in C# (LINQ)
Demonstrates the C# language features that are used to write LINQ query expressions.
Manipulating Data (C#) (LINQ to SQL)
Describes a LINQ to SQL scenario for adding, modifying, and deleting data in a database.
Simple Object Model and Query (C#) (LINQ to SQL)
Demonstrates how to create an entity class and a simple query to filter the entity class.
Using Only Stored Procedures (C#) (LINQ to SQL)
Demonstrates how to use LINQ to SQL to access data by executing only stored procedures.
Querying Across Relationships (C#) (LINQ to SQL)
Demonstrates the use of LINQ to SQL associations to represent foreign-key relationships in a database.
Writing a Visualizer in C#
Shows how to write a simple visualizer by using C#.
Related sections
Deployment Samples and Walkthroughs
Provides step-by-step examples of common deployment scenarios.
See also
C# Programming Guide
Visual Studio Samples