C# Collections
C# Collections
Programming Concepts
Assemblies and the Global Assembly Cache
Asynchronous Programming with async and await
Attributes
Caller Information
Collections
Covariance and Contravariance
Expression Trees
Iterators
Language-Integrated Query (LINQ)
Object-Oriented Programming
Reflection
Serialization (C# )
Threading
Programming Concepts (C#)
1/5/2018 • 1 min to read • Edit Online
In This Section
TITLE DESCRIPTION
Assemblies and the Global Assembly Cache (C#) Describes how to create and use assemblies.
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.
Caller Information (C#) Describes how to obtain information about the caller of a
method. This information includes the file path and the line
number of the source code and the member name of the
caller.
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.
TITLE DESCRIPTION
Threading (C#) Provides an overview of the .NET threading model and shows
how to write code that performs multiple tasks at the same
time to improve the performance and responsiveness of your
applications.
Related Sections
Performance Tips Discusses several basic rules that may help you increase the
performance of your application.
Assemblies and the Global Assembly Cache (C#)
1/5/2018 • 3 min to read • Edit Online
Assemblies form the fundamental unit of deployment, version control, reuse, activation scoping, and security
permissions for a .NET-based application. Assemblies take the form of an executable (.exe) file or dynamic link
library (.dll) file, and are the building blocks of the .NET Framework. They provide the common language runtime
with the information it needs to be aware of type implementations. You can think of an assembly as a collection of
types and resources that form a logical unit of functionality and are built to work together.
Assemblies can contain one or more modules. For example, larger projects may be planned in such a way that
several individual developers work on separate modules, all coming together to create a single assembly. For more
information about modules, see the topic How to: Build a Multifile Assembly.
Assemblies have the following properties:
Assemblies are implemented as .exe or .dll files.
You can share an assembly between applications by putting it in the global assembly cache. Assemblies
must be strong-named before they can be included in the global assembly cache. For more information, see
Strong-Named Assemblies.
Assemblies are only loaded into memory if they are required. If they are not used, they are not loaded. This
means that assemblies can be an efficient way to manage resources in larger projects.
You can programmatically obtain information about an assembly by using reflection. For more information,
see Reflection (C#).
If you want to load an assembly only to inspect it, use a method such as ReflectionOnlyLoadFrom.
Assembly Manifest
Within every assembly is an assembly manifest. Similar to a table of contents, the assembly manifest contains the
following:
The assembly's identity (its name and version).
A file table describing all the other files that make up the assembly, for example, any other assemblies you
created that your .exe or .dll file relies on, or even bitmap or Readme files.
An assembly reference list, which is a list of all external dependencies—.dlls or other files your application
needs that may have been created by someone else. Assembly references contain references to both global
and private objects. Global objects reside in the global assembly cache, an area available to other
applications. Private objects must be in a directory at either the same level as or below the directory in which
your application is installed.
Because assemblies contain information about content, versioning, and dependencies, the applications you create
with C# do not rely on Windows registry values to function properly. Assemblies reduce .dll conflicts and make
your applications more reliable and easier to deploy. In many cases, you can install a .NET-based application simply
by copying its files to the target computer.
For more information see Assembly Manifest.
Creating an Assembly
Compile your application by clicking Build on the Build menu or by building it from the command line using the
command-line compiler. For details about building assemblies from the command line, see Command-line
Building With csc.exe.
NOTE
To build an assembly in Visual Studio, on the Build menu choose Build.
See Also
C# Programming Guide
Assemblies in the Common Language Runtime
Friend Assemblies (C#)
How to: Share an Assembly with Other Applications (C#)
How to: Load and Unload Assemblies (C#)
How to: Determine If a File Is an Assembly (C#)
How to: Create and Use Assemblies Using the Command Line (C#)
Walkthrough: Embedding Types from Managed Assemblies in Visual Studio (C#)
Walkthrough: Embedding Type Information from Microsoft Office Assemblies in Visual Studio (C#)
Asynchronous programming with async and await
(C#)
1/5/2018 • 16 min 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.
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.
The following example shows an async method. Almost everything in the code should look completely familiar to
you. The comments call out the features that you add to create the asynchrony.
You can find a complete Windows Presentation Foundation (WPF) example file at the end of this topic, and you can
download the sample from Async Sample: Example from "Asynchronous Programming with Async and Await".
// GetStringAsync returns a Task<string>. That means that when you await the
// task you'll get a string (urlContents).
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
// You can do work here that doesn't rely on the string from GetStringAsync.
DoIndependentWork();
If AccessTheWebAsync 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).
For more information, see "Return Types and Parameters" later in this topic.
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 the .NET Framework, see TPL and Traditional .NET
Framework Asynchronous Programming.
NOTE
If GetStringAsync (and therefore getStringTask ) is complete before AccessTheWebAsync awaits it, control
remains in AccessTheWebAsync . The expense of suspending and then returning to AccessTheWebAsync would be
wasted if the called asynchronous process ( getStringTask ) has already completed and AccessTheWebSync doesn't
have to wait for the final result.
Inside the caller (the event handler in this example), the processing pattern continues. The caller might do
other work that doesn't depend on the result from AccessTheWebAsync before awaiting that result, or the
caller might await immediately. The event handler is waiting for AccessTheWebAsync , and AccessTheWebAsync
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 urlContents .
8. When AccessTheWebAsync has the string result, the method can calculate the length of the string. Then the
work of AccessTheWebAsync 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.
For more information about control flow, see Control Flow in Async Programs (C#).
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 IO-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 threadpool.
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
// Calls to TaskOfTResult_MethodAsync
Task<int> returnedTaskTResult = TaskOfTResult_MethodAsync();
int intResult = await returnedTaskTResult;
// or, in a single statement
int intResult = await TaskOfTResult_MethodAsync();
// Calls to Task_MethodAsync
Task returnedTask = Task_MethodAsync();
await returnedTask;
// or, in a single statement
await Task_MethodAsync();
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 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, which corresponds to Task<TResult>
IAsyncAction, which corresponds to Task
IAsyncActionWithProgress
IAsyncOperationWithProgress
For more information and an example, see Quickstart: using the await operator for asynchronous programming.
Naming convention
By convention, you append "Async" to the names of methods that have an async modifier.
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 Button1_Click .
Walkthrough: Accessing the Web by Shows how to convert a synchronous Async Sample: Accessing the Web
Using async and await (C#) WPF solution to an asynchronous WPF Walkthrough
solution. The application downloads a
series of websites.
How to: Extend the async Walkthrough Adds Task.WhenAll to the previous
by Using Task.WhenAll (C#) walkthrough. The use of WhenAll
starts all the downloads at the same
time.
How to: Make Multiple Web Requests Demonstrates how to start several Async Sample: Make Multiple Web
in Parallel by Using async and await tasks at the same time. Requests in Parallel
(C#)
Async Return Types (C#) Illustrates the types that async methods
can return and explains when each type
is appropriate.
Control Flow in Async Programs (C#) Traces in detail the flow of control Async Sample: Control Flow in Async
through a succession of await Programs
expressions in an asynchronous
program.
Fine-Tuning Your Async Application Shows how to add the following Async Sample: Fine Tuning Your
(C#) functionality to your async solution: Application
WhenAny: Bridging between the .NET Shows how to bridge between Task Async Sample: Bridging between .NET
Framework and the Windows Runtime types in the .NET Framework and and Windows Runtime (AsTask and
IAsyncOperations in the Windows WhenAny)
Runtime so that you can use WhenAny
with a Windows Runtime method.
TITLE DESCRIPTION SAMPLE
Async Cancellation: Bridging between Shows how to bridge between Task Async Sample: Bridging between .NET
the .NET Framework and the Windows types in the .NET Framework and and Windows Runtime (AsTask &
Runtime IAsyncOperations in the Windows Cancellation)
Runtime so that you can use
CancellationTokenSource with a
Windows Runtime method.
Using Async for File Access (C#) Lists and demonstrates the benefits of
using async and await to access files.
Complete example
The following code is the MainWindow.xaml.cs file from the Windows Presentation Foundation (WPF) application
that this topic discusses. You can download the sample from Async Sample: Example from "Asynchronous
Programming with Async and Await".
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace AsyncFirstExample
{
public partial class MainWindow : Window
{
// Mark the event handler with async so you can use await in it.
private async void StartButton_Click(object sender, RoutedEventArgs e)
{
// Call and await separately.
//Task<int> getLengthTask = AccessTheWebAsync();
//// You can do independent work here.
//int contentLength = await getLengthTask;
resultsTextBox.Text +=
String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
}
// GetStringAsync returns a Task<string>. That means that when you await the
// task you'll get a string (urlContents).
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
// You can do work here that doesn't rely on the string from GetStringAsync.
DoIndependentWork();
void DoIndependentWork()
{
resultsTextBox.Text += "Working . . . . . . .\r\n";
}
}
}
// Sample Output:
// Working . . . . . . .
See Also
async
await
Attributes (C#)
1/5/2018 • 4 min 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:
[System.Serializable]
public class SampleClass
{
// Objects of this type can be serialized.
}
using System.Runtime.InteropServices;
[System.Runtime.InteropServices.DllImport("user32.dll")]
extern static void SampleMethod();
using System.Runtime.InteropServices;
void MethodA([In][Out] ref double x) { }
void MethodB([Out][In] ref double x) { }
void MethodC([In, Out] ref double x) { }
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
Framework. 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
Framework.
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. Refer to the individual attribute's documentation for
information on default parameter values.
Attribute Targets
The target of an attribute is the entity to which the attribute applies. 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 it precedes. 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]
event Event
property 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: SomeAttr]
int Method2() { return 0; }
NOTE
Regardless of the targets on which SomeAttr is defined to be valid, the return target has to be specified, even if
SomeAttr 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
Caller Information (C#)
1/5/2018 • 2 min to read • Edit Online
By using Caller Info attributes, you can obtain information about the caller to a method. You can obtain file path of
the source code, the line number in the source code, and the member name of the caller. This information is
helpful for tracing, debugging, and creating diagnostic tools.
To obtain this information, you use attributes that are applied to optional parameters, each of which has a default
value. The following table lists the Caller Info attributes that are defined in the System.Runtime.CompilerServices
namespace:
Example
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:\Users\username\Documents\Visual Studio
2012\Projects\CallerInfoCS\CallerInfoCS\Form1.cs
// source line number: 31
Remarks
You must 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:
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 member 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
Attributes (C#)
Common Attributes (C#)
Named and Optional Arguments
Programming Concepts (C#)
Collections (C#)
1/19/2018 • 13 min 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 the .NET Framework. 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:
CLASS DESCRIPTION
For additional information, see Commonly Used Collection Types, Selecting a Collection Class, and
System.Collections.Generic.
System.Collections.Concurrent Classes
In the .NET Framework 4 or newer, 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:
CLASS DESCRIPTION
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[TKey] 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
Creating and Manipulating Collections
Selecting a Collection Class
Comparisons and Sorts Within Collections
When to Use Generic Collections
How to: Access a Collection Class with foreach
Covariance and Contravariance (C#)
1/5/2018 • 3 min 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 or newer 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
TITLE DESCRIPTION
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.
Expression Trees (C#)
1/5/2018 • 4 min 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 the .NET Framework 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.
For more information, see How to: Execute Expression Trees (C#).
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#)
Iterators (C#)
1/5/2018 • 7 min to read • Edit Online
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.
Iterators were introduced in C# in Visual Studio 2005.
In this topic
Simple Iterator
Creating a Collection Class
Using Iterators with a Generic List
Syntax Information
Technical Implementation
Use of Iterators
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.
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.
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 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 }
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 return type of the
iterator.
In C#, an iterator method cannot have any 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 is 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 re-iterate from the start, you must obtain a new iterator.
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
within the .NET Framework.
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)
1/5/2018 • 3 min 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.
Object-Oriented Programming (C#)
1/5/2018 • 9 min to read • Edit Online
C# provides full support for object-oriented programming including encapsulation, inheritance, and
polymorphism.
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.
This section describes the following concepts:
Classes and Objects
Class Members
Properties and Fields
Methods
Constructors
Finalizers
Events
Nested Classes
Access Modifiers and Access Levels
Instantiating Classes
Static Classes and Members
Anonymous Types
Inheritance
Overriding Members
Interfaces
Generics
Delegates
C# also provides a light version of classes called structures that are useful when you need to create large array of
objects and do not want to consume too much memory for that.
To define a structure:
struct SampleStruct
{
}
Class SampleClass
{
public string sampleField;
}
Properties have get and set procedures, which provide more control on how values are set or returned.
C# allows you either to create a private field for storing the property value or use so-called auto-implemented
properties that create this field automatically behind the scenes and provide the basic logic for the property
procedures.
To define an auto-implemented property:
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 { return _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 read-only or write-only.
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:
In most cases you declare a method within a class definition. However, C# also supports extension methods that
allow you to add methods to an existing class outside the actual definition of the class.
For more information, see:
Methods
Extension Methods
Constructors
Constructors are class methods that are executed automatically when an object of a given type is created.
Constructors usually initialize the data members of the new object. A constructor can run only once when a class is
created. Furthermore, the code in the constructor always runs before any other code in a class. However, you can
create multiple constructor overloads in the same way as for any other method.
To define a constructor for a class:
public class SampleClass
{
public SampleClass()
{
// Add code here
}
}
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:
C# MODIFIER DEFINITION
public The type or member can be accessed by any other code in the
same assembly or another assembly that references it.
C# MODIFIER DEFINITION
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:
C# MODIFIER DEFINITION
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();
}
Generics
Classes, structures, interfaces and methods in the .NET Framework 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:
Public class SampleGeneric<T>
{
public T Field;
}
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.
}
// Method that instantiates the delegate.
void SampleDelegate()
{
SampleDelegate sd = sampleMethod;
sd("Sample string");
}
}
See Also
C# Programming Guide
Reflection (C#)
1/5/2018 • 1 min 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 static method GetType - inherited by all types from the Object
base class - to obtain the type of a variable:
The following example uses reflection to obtain the full name of the loaded assembly.
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 the Common Language Runtime
Serialization (C# )
1/5/2018 • 3 min to read • Edit Online
Serialization is the process of converting an object into a stream of bytes in order 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, which carries not just the data, but information about the object's type, such as
its version, culture, and assembly name. From that stream, it 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 recreate it as needed, providing storage of
objects as well as data exchange. Through serialization, a developer can perform actions like sending the object to a
remote application by means of a Web Service, passing an object from one domain to another, passing an object
through a firewall as an XML string, or maintaining security or user-specific information across applications.
Making an Object Serializable
To serialize an object, you need the object to be serialized, a stream to contain the serialized object, and a
Formatter. System.Runtime.Serialization contains the classes necessary for serializing and deserializing objects.
Apply the SerializableAttribute attribute to a type to indicate that instances of this type can be serialized. A
SerializationException exception is thrown if you attempt to serialize but the type does not have the
SerializableAttribute attribute.
If you do not want a field within your class to be serializable, 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.
Designer Serialization
Designer serialization is a special form of serialization that involves the kind of object persistence usually
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.
Threading enables your C# program to perform concurrent processing so that you can do more than one
operation at a time. For example, you can use threading to monitor input from the user, perform background tasks,
and handle simultaneous streams of input.
Threads have the following properties:
Threads enable your program to perform concurrent processing.
The .NET Framework System.Threading namespace makes using threads easier.
Threads share the application's resources. For more information, see Using Threads and Threading.
By default, a C# program has one thread. However, auxiliary threads can be created and used to execute code in
parallel with the primary thread. These threads are often called worker threads.
Worker threads can be used to perform time-consuming or time-critical tasks without tying up the primary thread.
For example, worker threads are often used in server applications to fulfill incoming requests without waiting for
the previous request to be completed. Worker threads are also used to perform "background" tasks in desktop
applications so that the main thread--which drives user interface elements--remains responsive to user actions.
Threading solves problems with throughput and responsiveness, but it can also introduce resource-sharing issues
such as deadlocks and race conditions. Multiple threads are best for tasks that require different resources such as
file handles and network connections. Assigning multiple threads to a single resource is likely to cause
synchronization issues, and having threads frequently blocked when waiting for other threads defeats the purpose
of using multiple threads.
A common strategy is to use worker threads to perform time-consuming or time-critical tasks that do not require
many of the resources used by other threads. Naturally, some resources in your program must be accessed by
multiple threads. For these cases, the System.Threading namespace provides classes for synchronizing threads.
These classes include Mutex, Monitor, Interlocked, AutoResetEvent, and ManualResetEvent.
You can use some or all these classes to synchronize the activities of multiple threads, but some support for
threading is supported by the C# language. For example, the Lock Statement provides synchronization features
through implicit use of Monitor.
NOTE
Beginning with the .NET Framework 4, multithreaded programming is greatly simplified with the
System.Threading.Tasks.Parallel and System.Threading.Tasks.Task classes, Parallel LINQ (PLINQ), new concurrent collection
classes in the System.Collections.Concurrent namespace, and a new programming model that is based on the concept of
tasks rather than threads. For more information, see Parallel Programming.
Related Topics
TITLE DESCRIPTION
Parameters and Return Values for Multithreaded Procedures Describes how to pass and return parameters with
(C#) multithreaded applications.
Walkthrough: Multithreading with the BackgroundWorker Shows how to create a simple multithreaded application.
Component (C#)
Thread Timers (C#) Describes how to run procedures on separate threads at fixed
intervals.
Thread Pooling (C#) Describes how to use a pool of worker threads that are
managed by the system.
How to: Use a Thread Pool (C#) Demonstrates synchronized use of multiple threads in the
thread pool.