1. Dynamic Types: Introducing Dynamic Typing with the dynamic
Keyword
The dynamic
keyword in C# enables dynamic typing, meaning that the type of a variable is resolved at runtime instead of compile-time. This is useful when interacting with COM objects, dynamic languages, or handling objects whose types aren't known until runtime.
Example: Dynamic Type
class Program
{
static void Main()
{
dynamic obj = "Hello World"; // Type is determined at runtime
Console.WriteLine(obj.Length); // Accesses string's Length property
obj = 100;
Console.WriteLine(obj + 50); // Now it's an int, performs arithmetic
}
}
In the above example, the type of obj
changes dynamically at runtime, from a string
to an int
.
2. Named and Optional Parameters
Named parameters allow you to specify the arguments by the parameter name rather than the position. Optional parameters allow method parameters to be omitted when calling a method.
Example: Named and Optional Parameters
class Program
{
static void Greet(string name = "Guest", string message = "Welcome")
{
Console.WriteLine($"{message}, {name}!");
}
static void Main()
{
// Using optional parameters
Greet(); // Output: Welcome, Guest!
// Using named parameters
Greet(message: "Hello", name: "Alice"); // Output: Hello, Alice!
// Mixing named and optional parameters
Greet("John"); // Output: Welcome, John!
}
}
Here, name
and message
are optional, and named arguments let you specify them out of order.
3. Covariance and Contravariance: Variance Support for Generic Interfaces and Delegates
Covariance and contravariance allow you to use more derived or less derived types in generics, delegates, or interfaces. Covariance lets you assign a derived type where a base type is expected, and contravariance is the opposite.
- Covariance: More derived types can be used for return types.
- Contravariance: More derived types can be used for input parameters.
Example: Covariance and Contravariance with Delegates
class Animal { }
class Dog : Animal { }
public delegate Animal AnimalDelegate();
public delegate void DogDelegate(Dog dog);
class Program
{
static Dog GetDog() => new Dog();
static void HandleAnimal(Animal animal)
{
Console.WriteLine("Handling animal");
}
static void Main()
{
// Covariance: AnimalDelegate can point to a method returning a Dog (derived type)
AnimalDelegate animalDelegate = GetDog;
Animal animal = animalDelegate();
// Contravariance: DogDelegate can point to a method that takes an Animal (base type)
DogDelegate dogDelegate = HandleAnimal;
dogDelegate(new Dog());
}
}
Covariance allows AnimalDelegate
to reference a method that returns Dog
(a more derived type). Contravariance allows DogDelegate
to reference a method that takes Animal
.
4. Embedded Interop Types: Simplifying Interop with COM Components
Embedded Interop Types (also known as No PIA, or Primary Interop Assembly embedding) enable you to use COM components in .NET without having to deploy the entire PIA. When you add a COM reference in Visual Studio, it can embed the interop types directly into your assembly.
Example: Embedded Interop Types
Let's assume we are working with a COM component, such as Microsoft Excel. When embedding interop types, Visual Studio includes only the necessary types in your assembly, reducing dependencies.
- Add a COM reference (like Excel) and enable "Embed Interop Types."
- Use the COM types as normal, and the necessary types will be embedded.
using Excel = Microsoft.Office.Interop.Excel;
class Program
{
static void Main()
{
Excel.Application excelApp = new Excel.Application();
excelApp.Visible = true;
// No need to distribute a separate Interop assembly, types are embedded.
}
}
This simplifies deployment since only the types you use are embedded in your assembly.
5. Task Parallel Library (TPL): Easier Multithreading and Parallelism
The Task Parallel Library (TPL) is a high-level framework that simplifies the creation of multithreaded and parallel code. The key classes are Task
and Parallel
. The TPL abstracts away thread management, making multithreading easier to implement and manage.
Example: Using Task for Parallelism
using System;
using System.Threading.Tasks;
class Program
{
static void Main()
{
// Running tasks in parallel
Task task1 = Task.Run(() => DoWork(1));
Task task2 = Task.Run(() => DoWork(2));
// Wait for all tasks to complete
Task.WaitAll(task1, task2);
Console.WriteLine("All tasks completed.");
}
static void DoWork(int taskId)
{
Console.WriteLine($"Task {taskId} is starting.");
Task.Delay(1000).Wait(); // Simulate work
Console.WriteLine($"Task {taskId} is completed.");
}
}
Here, two tasks (task1
and task2
) run in parallel, and Task.WaitAll
ensures that the main thread waits for their completion.
Example: Parallel.For
Parallel.For
allows you to execute a loop in parallel.
using System;
using System.Threading.Tasks;
class Program
{
static void Main()
{
// Parallel loop to process data
Parallel.For(0, 10, i =>
{
Console.WriteLine($"Processing item {i}");
});
Console.WriteLine("All items processed.");
}
}
Parallel.For
is an easy way to process items concurrently, taking advantage of multiple CPU cores.
Summary of Key Points
- Dynamic Types (
dynamic
): Enables dynamic typing, allowing the type of variables to be determined at runtime. - Named and Optional Parameters: Simplify method calls by allowing parameters to be specified by name and to omit optional parameters.
- Covariance and Contravariance: Allow more flexibility in using derived and base types in generics, interfaces, and delegates.
- Embedded Interop Types: Reduce the need to deploy primary interop assemblies by embedding only the required COM interop types directly in your assembly.
- Task Parallel Library (TPL): Provides an easy-to-use framework for multithreading and parallel programming, utilizing
Task
andParallel
constructs for better performance.