Skip to content

Instantly share code, notes, and snippets.

@VenenJean
Last active September 13, 2023 16:08
Show Gist options
  • Save VenenJean/5d23834985de76af4fb424e821ce0cb2 to your computer and use it in GitHub Desktop.
Save VenenJean/5d23834985de76af4fb424e821ce0cb2 to your computer and use it in GitHub Desktop.

20 useful C# features

Null-Conditional Operator (?)

The null-conditional operator allows you to safely access properties or call methods on an object that might be null without causing a null reference exception.
Example: int? length = text?.Length;

String Interpolation...

String interpolation simplifies string formatting by allowing you to embed expressions directly within a string using the $ symbol.
Example: string name = "Alice"; string message = $"Hello, {name}!";

[...]with Format Strings

You can combine string interpolation with format strings to control the formatting of interpolated values.
Example: $"Today is {DateTime.Now:yyyy-MM-dd}"

Use format specifiers directly within interpolated strings or composite format strings to control the formatting of values.
Example:

decimal price = 19.99M;
// Same output - Formats 'price' as currency with 2 decimal places
string message = $"The price is: {price:C2}";
string message = string.Format("The price is: {0:C2}", price);

B - Binary
C - Curreny
D - Decimal
E - Exponential(scientific)
F - Fixed-point
G - General
N - Number
P - Percent
R - Round-trip
X - Hexadecimal

Expression-Bodied Members

You can use expression-bodied syntax to simplify the code for read-only properties, methods, and operators.
Example: public int Square(int x) => x * x;

Pattern Matching

Pattern matching simplifies complex conditional statements by providing a concise syntax for testing values against patterns.
Example: if (obj is int number) { /* use 'number' */ }

Local Functions

Local functions allow you to declare methods within methods, improving encapsulation and code organization.
Example:

int Add(int a, int b)
{
    int LocalAdd(int x, int y) => x + y;
    return LocalAdd(a, b);
}

Deconstruction

Deconstruction enables you to split a tuple or other data structure into individual variables easily.
Example: (int x, int y) = GetPoint();

Out Variables

You can declare and initialize variables directly in the argument list of a method using the out keyword.
Example: if (int.TryParse(input, out int result)) { /* use 'result' */ }

Discards (_)

Discards (_) allow you to ignore values in deconstruction or pattern matching when you're not interested in them.
Example: (int x, _) = GetPoint();

Tuple Types and Tuple Literals

Tuple types and literals enable you to work with lightweight data structures without creating custom classes or structures.
Example: (string Name, int Age) person = ("Alice", 30);

Default Literals

The default keyword allows you to get the default value of a data type without knowing the type in advance.
Example: int defaultValue = default; // '0' for int

Object Initializers

Object initializers allow you to create and initialize objects in a concise way.
Example: Person person = new Person { Name = "Alice", Age = 30 };

Extension Methods

Extension methods enable you to add new methods to existing types without modifying their source code.
Example: Adding a custom extension method to the string type.

public static class StringExtensions
{
    public static bool IsPalindrome(this string str)
    {
        // Implementation to check if 'str' is a palindrome
    }
}

Async/Await Pattern

Asynchronous programming with async and await allows you to write non-blocking code, making your applications more responsive.
Example: async Task<string> DownloadDataAsync() { /* async operation */ }

Lambda Expressions

Lambda expressions enable you to define inline, anonymous functions, making it easier to work with delegates, LINQ, and functional programming.
Example: Func<int, int> square = x => x * x;

Local Type Inference (var)

The var keyword allows the compiler to infer the data type of a variable based on the assigned value, reducing the need for explicit type declarations.
Example: var number = 42; // 'number' is of type int

Caller Information Attributes

Caller Information attributes (CallerMemberName, CallerFilePath, CallerLineNumber) provide information about the caller of a method or property, aiding in debugging and logging.
Example:

public void Log(string message, [CallerMemberName] string caller = "")
{
    Console.WriteLine($"Caller: {caller}, Message: {message}");
}

Custom Exception Filters

Custom exception filters allow you to specify conditions under which an exception handler should execute, providing more fine-grained control over exception handling.
Example:

try {
    // ...
} catch (Exception ex) when (ex is IOException ioException) {
    // Handle IOException specifically
}

Tuple Deconstruction in Foreach

You can deconstruct tuples directly in a foreach loop, making it easier to iterate over collections of tuples.
Example:

var points = new List<(int X, int Y)> { (1, 2), (3, 4), (5, 6) };
foreach (var (x, y) in points) {
    Console.WriteLine($"X: {x}, Y: {y}");
}

Attribute-Based Routing (ASP.NET Core)

In ASP.NET Core, attribute-based routing allows you to define routing information directly on controller actions, making routing configuration more concise.
Example:

[Route("api/[controller]")]
public class UsersController : ControllerBase {
    [HttpGet("{id}")]
    public IActionResult GetUser(int id) { /* ... */ }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment