C# Interview Questions

Created
Aug 22, 2024 02:41 AM

Fundamentals

C# Versions

C# 1.0 (Released 2002)

  • Key Features:
    • Classes
    • Structs
    • Interfaces
    • Events
    • Properties
    • Delegates

C# 2.0 (Released 2005)

  • Key Features:
    • Generics
    • Partial Classes
    • Static Classes
    • Nullable Types
    • Co-variance and Contravariance

C# 3.0 (Released 2007)

  • Key Features:
    • LINQ (Language Integrated Query)
    • Lambda Expressions
    • Extension Methods
    • Anonymous Types
    • Implicitly Typed Variables (using var)
    • Expression Trees

C# 4.0 (Released 2010)

  • Key Features:
    • Dynamic Binding (using dynamic)
    • Named Arguments
    • Optional Parameters
    • Improved COM Interoperability

C# 5.0 (Released 2012)

  • Key Features:
    • Async and Await for asynchronous programming
    • Caller Information Attributes

C# 6.0 (Released 2015)

  • Key Features:
    • String Interpolation
    • Null-Conditional Operators
    • Expression-bodied Members
    • Auto-Property Initializers
    • Static Imports

C# 7.0 (Released 2017)

  • Key Features:
    • Tuples
    • Pattern Matching
    • Local Functions
    • Ref locals and returns
    • Out Variables

C# 7.1 (Released 2017)

  • Key Features:
    • Default Literal
    • Async Main method
    • Language Versioning

C# 7.2 (Released 2017)

  • Key Features:
    • Non-constant default values
    • Enhanced performance for safe code

C# 7.3 (Released 2018)

  • Key Features:
    • Improved pattern matching
    • New compiler options

C# 8.0 (Released 2019)

  • Key Features:
    • Nullable Reference Types
    • Default Interface Methods
    • Switch Expressions
    • Using Declarations
    • Asynchronous Streams

C# 9.0 (Released 2020)

  • Key Features:
    • Records (for immutable data)
    • Init-only Properties
    • Top-level Statements
    • Pattern Matching Enhancements

C# 10.0 (Released 2021)

  • Key Features:
    • Global usings: Use of the global keyword to apply using directives across all files.
    • Null parameter checking: Simplifies null checks for parameters.
    • Constant interpolated strings: Allows constant strings to be initialized using interpolation.
    • Record structs: Introduces value-type records for immutable data structures.
    • Extended property patterns: Simplifies accessing nested properties in patterns.
    • Top-level statements: Allows writing code without the need for a Main method in simple applications.
    • Lambda improvements: Enhancements to lambda expressions for better usability.

C# 11.0 (Released 2022)

  • Key Features:
    • Raw string literals: Simplifies multi-line string handling without escaping.
    • Required members: Allows specifying that certain properties must be initialized during object creation.
    • Generic math: Introduces support for mathematical operations on generic types.
    • New pattern matching enhancements: Includes improvements for switch expressions and pattern matching capabilities.
    • Improvements to records: Enhancements to record types for better functionality and usability.

C# 12.0 (Released November 2023)

  • Key Features:
    • Primary Constructors
    • Collection Expressions
    • Inline Arrays
    • Optional Parameters in Lambda Expressions
    • Alias Any Type
  • Default interface methods: Allows interfaces to have default implementations.
  • New language features for pattern matching: Further enhancements to pattern matching capabilities.
  • Improvements to async/await: Enhancements for better handling of asynchronous programming.
  • Static abstract members in interfaces: Allows interfaces to define static members.

C# 13.0 (November 2024)

  • Enhanced params collections: The params keyword now works with any collection type.
  • New lock type: Introduces System.Threading.Lock for better thread synchronization.
  • Partial properties: Allows separating property declaration from implementation.
  • New escape sequence: Introduces \e for the escape character.
  • Implicit indexer access: Enables the use of indexers directly within object initializers.

Operators

Operator Category
Operators
Arithmetic Operators
+-*/%++--
Relational Operators
==!=><>=<=
Logical Operators
&&, `
Bitwise Operators
&, `
Assignment Operators
=+=-=*=/=%=<<=>>=&=^=, `
Type Testing Operators
isas
Lambda Operator
=>
Member Access Operators
. (dot operator for accessing members)
Indexers
[] (used to access elements in arrays or collections)
Pointer Operators
*&
Operator
Description
Example Usage
Range Operator (..)
Used to create a range of values. It can be used with arrays and collections to specify a range of indices.
var range = 0..5; (creates a range from 0 to 4)
Index Operator (^)
Used to specify an index from the end of a collection. It allows you to access elements from the end without calculating the index.
var lastElement = array[^1]; (accesses the last element)
Null Coalescing Operator (??)
Returns the left-hand operand if it is not null; otherwise, it evaluates and returns the right-hand operand.
string name = possiblyNullName ?? "Default Name";
Null Coalescing Assignment Operator (??=)
Assigns the right-hand operand to the left-hand operand only if the left-hand operand is null.
someValue ??= defaultValue;
is Operator
Used for type checking. It evaluates to true if the operand is of the specified type or a derived type.
if (obj is string) { ... }
as Operator
Used for safe casting. It attempts to cast the operand to the specified type and returns null if the cast fails.
string str = obj as string;
sizeof Operator
Returns the size of a data type in bytes.
int size = sizeof(int);
typeof Operator
Returns the System.Type object representing the operand's type.
Type t = typeof(string);
nameof Operator
Returns the name of a variable, type, or member as a string.
string name = nameof(myVariable);
Conditional Operator (?:)
The ternary operator. It evaluates an expression and returns one of two values depending on whether the expression evaluates to true or false.
int result = (a > b) ? a : b;

Type Conversions in C#

1. Implicit Type Conversion

Implicit type conversion happens automatically by the compiler when the destination type is larger than the source type. This is safe because no data will be lost during the conversion.Examples of implicit conversions:
  • Converting int to longfloatdouble, or decimal
  • Converting char to int
  • Converting byte or short to int

2. Explicit Type Conversion (Type Casting)

Explicit type conversion requires a cast operator and is used when converting to a type that has a different representation. This can result in a loss of data or an invalid representation.Examples of explicit conversions:
  • Converting double to int
  • Converting char to byte
  • Converting int to char

3. Boxing

Boxing is the process of converting a value type (such as intfloatchar, etc.) to a reference type (specifically, to an  object). Boxing can incur a performance overhead because it involves allocating memory on the heap and copying the value from the stack to the heap.
csharpint number = 123; // Value type object boxedNumber = number; // Boxing

4. Unboxing

Unboxing is the reverse process of boxing. It involves converting a reference type (specifically, an  object) back to a value type. Unboxing requires an explicit cast. Unboxing also incurs a performance cost, as it involves checking the type of the object and copying the value back to the stack.
csharpobject boxedNumber = 123; // Boxing int number = (int)boxedNumber; // Unboxing

Data Types in C#

  1. Primitive - byte, sbyte, short, ushort, int, uint, long, ulong, float, double, decimal, char, bool
  1. Non-primitive - string, object, class, interface, array, delegate, dynamic

What are the 2 types of data types available in C#?

  1. Value Types - Structs, Primitives, Enums
  1. Reference Types - Non-primitive
Feature
Value Types
Reference Types
Storage Location
Stored on the stack
Stored on the heap
Data Storage
Contains the actual value
Contains a reference to the data
Memory Allocation
Allocated at compile time
Allocated at runtime
Default Value
Cannot be null (default is zero)
Can be null
Immutability
Generally immutable
Can be mutable
Comparison
Compared by value
Compared by reference
Examples
intfloatcharbool
stringobjectclassarray
Performance
Generally faster due to stack allocation
Slower due to heap allocation
Inheritance
Cannot inherit from other types (sealed)
Can inherit from other classes

Constructors in C#

Constructors in C# are special methods that are automatically called when an object of a class is created. They are used to initialize the state of an object by setting the values of its fields. Here are the key points about constructors in C#:

Definition and Syntax

  • A constructor has the same name as the class it belongs to.
  • It does not have a return type, not even void.
  • The constructor's method signature includes only an optional access modifier and the parameter list.
    • public class Person { private string name; public Person(string name) { this.name = name; } }

Types of Constructors

  1. Default Constructor: A constructor with no parameters that initializes the object with default values. If no constructor is defined, C# provides a default constructor that initializes fields to their default values (0 for numbers, null for references).
  1. Parameterized Constructor: A constructor that takes one or more parameters to initialize the object with specific values.
  1. Copy Constructor: A constructor that creates a new object by copying the values of an existing object of the same type.
  1. Static Constructor: A constructor that initializes the static fields of a class. It is called automatically before the class is used for the first time.
  1. Private Constructor: A private constructor in C# is a special instance constructor that is declared with the ‘private’ access modifier. It can only be called within the class itself and is often used for specific purposes, such as implementing design patterns like the Singleton pattern or providing controlled instance creation.

Characteristics

  • A class can have multiple constructors with different parameter lists (constructor overloading).
  • Constructors cannot be abstractvirtual, or static (except for static constructors).
  • Constructors cannot have the same name as any instance method in the class.
  • Constructors can have access modifiers to control their visibility.

Abstract Class vs Interface

Abstract classes and interfaces in C# are both essential tools for implementing abstraction and polymorphism, but they serve different purposes and have distinct characteristics. Below is a detailed comparison of the two.

Key Similarities

  • Define Behavior Without Implementation: Both abstract classes and interfaces allow you to define behavior that must be implemented by derived classes or implementing classes.
  • Cannot Be Instantiated: Neither abstract classes nor interfaces can be instantiated directly.
  • Contain Abstract Methods: Both can declare methods that must be implemented by derived classes or implementing classes.

Key Differences

Feature
Abstract Class
Interface
Instantiation
Cannot be instantiated
Cannot be instantiated
Inheritance
A class can inherit from only one abstract class
A class can implement multiple interfaces
Method Implementation
Can contain both abstract and concrete methods
Can only contain method signatures (until C# 8.0, where default implementations were introduced)
Fields
Can contain fields
Cannot contain fields; can only declare properties, methods, events, and indexers
Constructors
Can have constructors
Cannot have constructors
Access Modifiers
Can have access modifiers (public, protected, etc.)
Members are public by default
State Management
Can maintain state through fields
Cannot maintain state
Use Cases
Suitable for closely related classes with common functionality
Suitable for defining a contract for unrelated classes
Adding New Members
Easier to add new methods without breaking existing implementations
Adding new methods can break existing implementations unless default implementations are used (C# 8.0 and later)

When to Use Each

  • Abstract Class: Use when you want to provide a common base class with some shared functionality. It is ideal when you have a class hierarchy where derived classes share common behavior or state.
  • Interface: Use when you want to define a contract that can be implemented by multiple classes, especially when those classes are not related. Interfaces are more flexible as they allow a class to implement multiple interfaces.

Example Scenarios

  • Abstract Class Example:
    • public abstract class Animal { public abstract void Speak(); public void Sleep() { Console.WriteLine("Sleeping..."); } } public class Dog : Animal { public override void Speak() { Console.WriteLine("Bark"); } }
  • Interface Example:
    • public interface IDamageable { void TakeDamage(int amount); } public class Player : IDamageable { public void TakeDamage(int amount) { Console.WriteLine($"Player takes {amount} damage."); } }

Field and Property

Feature
Field
Property
Syntax
type fieldName;
type PropertyName { get; set; }
Accessibility
Same accessibility for reading and writing
Getter and setter can have different accessibility
Encapsulation
Directly exposes the underlying variable
Can add extra logic and validation
Memory Footprint
Increases the memory footprint proportionally
Does not increase the memory footprint
Interfaces
Cannot be declared in interfaces
Can be part of an interface contract
Initialization
Can be initialized inline or in constructor
Can be initialized inline or in constructor
Backing Field
No backing field is required
Typically has a private backing field
Naming Convention
Use camelCase or PascalCase
Use PascalCase
Use Case
Useful for internal implementation details
Provides a flexible way to expose class data

Types of classes

Class Type
Description
Example Syntax
Regular Class
The most common type of class that can be instantiated and can contain methods, properties, and fields.
public class MyClass { }
Abstract Class
A class that cannot be instantiated and is meant to be a base class for other classes. It can contain abstract methods (without implementation) and concrete methods.
public abstract class MyBaseClass { public abstract void MyMethod(); }
Sealed Class
A class that cannot be inherited. This is used to prevent further derivation from the class.
public sealed class MySealedClass { }
Static Class
A class that cannot be instantiated and can only contain static members. It is used for utility or helper methods.
public static class MyStaticClass { public static void MyMethod() { } }
Partial Class
A class that can be split into multiple files. This allows for better organization of code and separation of concerns.
partial class MyPartialClass { }
Nested Class
A class defined within another class. It can be used to logically group classes that are only used in one place.
public class OuterClass { public class InnerClass { } }

Equality Operator(==) and Equals()

Feature
== Operator
Equals() Method
Type
Operator
Method
Comparison Type
Compares reference identity for reference types; compares values for value types
Compares content of objects, can be overridden
Default Behavior
For reference types, checks if both references point to the same object in memory
Checks if the contents of the objects are equal
Null Handling
Can handle null values without throwing exceptions
Throws a NullReferenceException if called on a null object
Overloading
Can be overloaded in user-defined types
Can be overridden in user-defined types
Performance
Generally faster for reference types due to direct comparison
Slightly slower due to method call overhead
Use Cases
Use for checking if two references point to the same object or for value types
Use for checking logical equality of object contents
Example with Strings
string str1 = "Hello"; string str2 = "Hello"; str1 == str2; // true
str1.Equals(str2); // true
Example with Reference Types
object obj1 = new object(); object obj2 = new object(); obj1 == obj2; // false
obj1.Equals(obj2); // false

Difference b/w Const vs ReadOnly vs Static ReadOnly

Feature
const
readonly
static readonly
Definition
A constant field whose value is set at compile time and cannot be changed.
A field that can only be assigned during declaration or in a constructor.
A static field that can only be assigned during declaration or in a static constructor.
Initialization
Must be initialized at the time of declaration.
Can be initialized at declaration or in any constructor of the class.
Can be initialized at declaration or in a static constructor.
Scope
Implicitly static; belongs to the type itself.
Instance-level; belongs to an instance of the class.
Static; belongs to the type itself.
Value Change
Cannot be changed after initialization.
Can be assigned a value only once, either at declaration or in a constructor.
Can be assigned a value only once, either at declaration or in a static constructor.
Usage Context
Use when the value is known at compile time and will not change.
Use when the value may be set at runtime but should not change after initialization.
Use when the value is constant for all instances and should not change after initialization.
Example
const int MaxValue = 100;
readonly int instanceValue; (assigned in constructor)
static readonly int StaticValue = 200; (assigned at declaration)

Advance

Anonymous types

  • Anonymous types are class types that derive directly from System.Object.
  • They allow creating a new type without explicitly defining it first.

Key Features

  • Created using the new operator with an object initializer syntax.
  • Contain one or more public read-only properties. No other class members are allowed.
  • The property initializer expressions cannot be null, anonymous functions, or pointer types.
  • Inferred type based on the properties specified in the object initializer.
  • Stored in implicitly typed variables declared using var.
  • Scope is limited to the method where they are defined.
  • Cannot be returned from a method or passed as a parameter (except as object).
  • Two anonymous types are considered equal if all their properties are equal.

Example

var student = new { Id = 1, Name = "John Doe" }; Console.WriteLine(student.Name); // Output: John Doe

Garbage Collection in .NET

Garbage collection in C# is an automatic memory management process that helps reclaim memory occupied by objects that are no longer in use. This mechanism is a core feature of the .NET Framework, allowing developers to focus on application logic without worrying about manual memory management.

How Garbage Collection Works

The garbage collector (GC) operates in several phases:
  1. Marking Phase: The GC identifies live objects by traversing the object graph starting from root references. It creates a list of all objects that are still reachable.
  1. Relocating Phase: After marking, the GC updates references of the live objects to ensure they point to their new locations in memory, which may change during the compacting phase.
  1. Compacting Phase: The GC reclaims memory by removing dead objects (those not marked as live) and compacts the remaining live objects to reduce fragmentation. This involves moving the live objects towards the start of the heap, which optimizes memory usage and allocation speed.

Generations in Garbage Collection

C# employs a generation-based approach to optimize the garbage collection process, categorizing objects into three generations:
  • Generation 0: This generation contains short-lived objects. Most objects are collected in this generation, making it the most frequently garbage-collected space.
  • Generation 1: Objects that survive a collection in Generation 0 are promoted to Generation 1, which is collected less frequently.
  • Generation 2: Long-lived objects that survive multiple collections are moved to Generation 2, which is collected even less often. This tier is generally stable and contains objects that are expected to remain in memory for a longer duration.

Benefits of Garbage Collection

  • Automatic Memory Management: Developers do not need to manually allocate or free memory, reducing the likelihood of memory leaks and dangling pointers.
  • Performance: While garbage collection can introduce pauses in application performance, it generally operates in the background with minimal impact on the application's responsiveness.
  • Memory Safety: The GC ensures that objects cannot access memory allocated to other objects, enhancing the safety of the application

Managed and Unmanaged code

Managed Code
The code which is executed by CLR (Common Language Runtime) is called Managed Code, any application which is developed in .Net framework is going to work under CLR, the CLR internally uses the Garbage Collector to clear the unused memory and also used the other functionalities like CTS, CAS etc.
notion image
Unmanaged Code
The unmanaged code is basically developed using other languages (other than .Net Framework), so it uses its own language runtime to execute the applications. The application runtime will take care of its memory management, security etc...
Feature
Managed Code
Unmanaged Code
Execution Environment
Executed by the Common Language Runtime (CLR)
Executed directly by the operating system
Memory Management
Automatic memory management via garbage collection
Manual memory management using pointers
Security
Benefits from CLR security features
Fewer security restrictions, higher risk of vulnerabilities
Compilation
Compiled to Intermediate Language (IL) and JIT compiled to native code
Compiled directly to native machine code
Performance
Slightly lower performance due to CLR overhead
Higher performance due to direct access to system resources
Examples
.NET applications written in C#, VB.NET, F#, etc.
Native applications written in C/C++

What is a delegate in .NET?

Delegate is one of the base types in .NET. Delegate is a class, which is used to create and invoke delegates at runtime.

Key Characteristics of Delegates

  • Type Safety: Delegates ensure that the method signature (return type and parameters) matches the delegate type, preventing runtime errors.
  • Encapsulation: Delegates encapsulate a method, allowing methods to be passed as parameters, stored in variables, or invoked dynamically.
  • Multicast Capability: Delegates can reference multiple methods at once, allowing for the invocation of several methods in a single call.

Built-in Delegates

C# provides several built-in delegate types that simplify common scenarios:
  • Func<T, TResult>: Represents a method that takes parameters of type T and returns a value of type TResult. For example:
    • csharpFunc<int, int, int> multiply = (a, b) => a * b;
  • Action<T>: Represents a method that takes parameters of type T and does not return a value. For example:
    • csharpAction<string> printMessage = message => Console.WriteLine(message);
  • Predicate<T>: Represents a method that takes a parameter of type T and returns a boolean. For example:
    • csharpPredicate<int> isEven = number => number % 2 == 0;

Static

In C#, static classes and members provide a way to define functionality that does not require an instance of a class. This can be particularly useful for utility functions, constants, or shared data. Here’s a comprehensive overview of static classes, methods, and their characteristics.

Static Class

A static class is a class that cannot be instantiated, meaning you cannot create an object of that class. It is declared using the static keyword and can only contain static members (methods, properties, fields, etc.).

Characteristics of Static Classes

  • Cannot be instantiated: You cannot create an instance of a static class.
  • Only contains static members: All members of a static class must be static. Attempting to define an instance member will result in a compile-time error.
  • Sealed: Static classes are implicitly sealed, meaning they cannot be inherited.
  • Memory Lifetime: A static class remains in memory for the lifetime of the application domain.
  • Static Constructor: A static class can have a static constructor, which initializes static members when the class is loaded. Also, used as singleton.

Example of a Static Class

public static class MathUtility { public static double Pi = 3.14; public static double Square(double number) { return number * number; } } // Usage double area = MathUtility.Square(5); // Calls the static method Console.WriteLine("Area: " + area);

Static Members

Static members belong to the class itself rather than any instance of the class. They can be accessed without creating an instance of the class.

Types of Static Members

  1. Static Fields: Variables that are shared across all instances of a class. They retain their value for the lifetime of the application.
  1. Static Methods: Methods that can be called without creating an instance of the class. They cannot access instance members directly.
  1. Static Properties: Properties that are accessed through the class name rather than an instance.
  1. Static Events: Events that can be subscribed to without an instance of the class.

Example of Static Members in a Non-Static Class

public class Counter { public static int Count = 0; public Counter() { Count++; } } // Usage Counter c1 = new Counter(); Counter c2 = new Counter(); Console.WriteLine("Total Count: " + Counter.Count); // Outputs: Total Count: 2

Static Methods

Static methods can be defined in both static and non-static classes. They are called on the class itself rather than on an instance.

Characteristics of Static Methods

  • Cannot access instance members: Static methods cannot directly access instance variables or instance methods.
  • Can be overloaded: Static methods can have multiple definitions with different parameters.
  • Cannot be overridden: Since they belong to the class, not to instances, static methods cannot be overridden in derived classes.

Example of Static Method

public class Utility { public static int Add(int a, int b) { return a + b; } } // Usage int sum = Utility.Add(5, 10); // Calls the static method Console.WriteLine("Sum: " + sum);

Static Constructors

A static constructor is used to initialize static members of a class. It is called automatically before any static member is accessed or any static method is called.

Characteristics of Static Constructors

  • No parameters: Static constructors cannot take parameters.
  • Called once: They are called only once, when the class is loaded.
  • Cannot be called directly: You cannot call a static constructor directly.

Example of Static Constructor

public static class Configuration { public static string ConnectionString; static Configuration() { ConnectionString = "Server=myServer;Database=myDB;User Id=myUser;Password=myPass;"; } } // Usage Console.WriteLine(Configuration.ConnectionString); // Outputs the connection string

When to Use Static Classes and Members

  • Utility Functions: For functions that do not rely on instance data, such as mathematical calculations (e.g., Math.Sqrt()).
  • Constants: To define constants that are shared across the application.
  • Shared State: When you need to maintain a state that is shared across all instances of a class.
  • Factory Methods: To create instances of classes without exposing the instantiation logic.
 

Lazy<T>

Lazy<T> is a class in the .NET framework that provides support for lazy initialization, allowing you to defer the creation of an object until it is actually needed. This can improve performance, especially when the initialization of the object is resource-intensive or when it may not be needed during the application's lifetime.

Key Features of Lazy<T>

  1. Deferred Initialization: The object of type T is created only when the Value property is accessed for the first time, not when the Lazy<T> instance is created.
  1. Thread Safety: Lazy<T> provides thread-safe initialization by default. This means that if multiple threads try to access the Value property simultaneously, the class ensures that the object is created only once.
  1. Custom Initialization Logic: You can provide a delegate (e.g., a lambda expression) to the Lazy<T> constructor, which defines how to create the instance of T.
  1. Control Over Thread Safety: You can specify the thread-safety mode using the LazyThreadSafetyMode enumeration, allowing you to choose between different levels of thread safety.

Constructors

  • Lazy<T>(): Initializes a new instance of the Lazy<T> class using the default constructor of the target type.
  • Lazy<T>(Func<T>): Initializes a new instance of the Lazy<T> class, using a delegate to specify how to create the target type.
  • Lazy<T>(Func<T>, Boolean): Initializes a new instance of the Lazy<T> class, specifying whether the initialization is thread-safe.
  • Lazy<T>(Func<T>, LazyThreadSafetyMode): Initializes a new instance of the Lazy<T> class, specifying the delegate and the thread-safety mode.

Example Usage

Here’s a simple example demonstrating how to use Lazy<T>:
using System; public class ExpensiveObject { public ExpensiveObject() { // Simulate expensive initialization Console.WriteLine("ExpensiveObject created!"); } public void DoSomething() { Console.WriteLine("Doing something..."); } } public class Program { private static readonly Lazy<ExpensiveObject> lazyExpensiveObject = new Lazy<ExpensiveObject>(() => new ExpensiveObject()); public static void Main() { Console.WriteLine("Before accessing the Lazy object."); // The ExpensiveObject is not created yet Console.WriteLine("IsValueCreated: " + lazyExpensiveObject.IsValueCreated); // Accessing the Value property triggers the creation of ExpensiveObject var obj = lazyExpensiveObject.Value; obj.DoSomething(); // Now the object has been created Console.WriteLine("IsValueCreated: " + lazyExpensiveObject.IsValueCreated); } }

Output

Before accessing the Lazy object. IsValueCreated: False ExpensiveObject created! Doing something... IsValueCreated: True

When to Use Lazy<T>

  • Resource-Intensive Objects: When the creation of an object is costly in terms of time or resources, and it may not be needed immediately.
  • Conditional Initialization: When you want to delay the creation of an object until it is confirmed to be necessary.
  • Singleton Implementations: Lazy<T> can simplify the implementation of thread-safe singletons, as it handles the lazy initialization and thread safety automatically.

Extension Methods

Extension methods in C# allow developers to add new methods to existing types without modifying their source code, creating a new derived type, or recompiling the original type. This feature enhances the functionality of types in a clean and maintainable way. Here’s an overview of extension methods based on the search results.

Key Features of Extension Methods

  • Static Methods: Extension methods are defined as static methods in a static class.
  • this Keyword: The first parameter of the method must be preceded by the this keyword, indicating which type is being extended.
  • Instance Method Syntax: Once defined, extension methods can be called as if they were instance methods on the extended type.
  • Namespace Scope: Extension methods are only available when the namespace containing them is imported with a using directive.
  1. Define a Static Class: Create a static class to contain the extension method.
  1. Define the Extension Method: Implement the method as a static method with the first parameter prefixed by this.
  1. Use the Extension Method: To use the extension method, import the namespace and call it like an instance method.

Example of Extension Method

Here’s a simple example demonstrating how to create and use an extension method:
using System; namespace StringExtensions { public static class StringHelper { // Extension method to reverse a string public static string Reverse(this string input) { char[] chars = input.ToCharArray(); Array.Reverse(chars); return new string(chars); } } } class Program { static void Main(string[] args) { string example = "Hello, World!"; string reversed = example.Reverse(); // Calling the extension method Console.WriteLine(reversed); // Output: !dlroW ,olleH } }

Ref Vs Out

Feature
ref
out
in
Definition
Passes an argument by reference, allowing the method to modify the value of the argument.
Similar to ref, but used to return multiple values.
Passes an argument by reference, but the parameter is read-only within the method.
Initialization Requirement
The variable must be initialized before being passed to the method.
The variable does not need to be initialized before being passed, but must be assigned a value within the method before return.
The variable must be initialized before being passed to the method.
Modification
Allows the method to modify the value of the argument.
The method must assign a value to the out parameter before returning.
The method cannot modify the value of the argument; it is read-only.
Use Case
When you want to modify the variable in the method.
When you want a method to return multiple values.
When you want to pass a large structure without copying it, but do not want to modify it.
Example
void ModifyValue(ref int number) { number += 10; }
void GetValues(out int a, out int b) { a = 1; b = 2; }
void DisplayValue(in int number) { Console.WriteLine(number); }

Parameter modifiers

Keyword
Description
Initialization Requirement
Use Case
Example
ref
Passes an argument by reference, allowing the method to modify the value of the argument.
The variable must be initialized before being passed.
When you want to modify the variable in the method.
void ModifyValue(ref int number) { number += 10; }
out
Similar to ref, but used to return multiple values. The variable does not need to be initialized.
Must be assigned a value within the method before return.
When you want a method to return multiple values.
void GetValues(out int a, out int b) { a = 1; b = 2; }
in
Passes an argument by reference, but the parameter is read-only within the method.
The variable must be initialized before being passed.
When you want to pass a large structure without copying it, but do not want to modify it.
void DisplayValue(in int number) { Console.WriteLine(number); }
params
Allows a method to accept a variable number of arguments as an array.
The parameter does not need to be initialized explicitly.
When you want to pass a variable number of arguments to a method.
void PrintNumbers(params int[] numbers){ foreach (var number in numbers) { Console.WriteLine(number); }}

Thread vs Task

Feature
Task
Thread
Abstraction Level
Higher-level abstraction for asynchronous programming
Lower-level construct representing OS threads
Memory Management
More lightweight and efficient, managed by TPL
Uses its own system resources like memory and CPU
Execution Control
Simplifies concurrency management
Provides fine-grained control and allows setting priority
Blocking the Main Thread
Does not block the main application thread from exiting
Blocks the main thread from exiting until it completes
Ease of Use
Easier to use and compose, supports cancellation
More complex to manage and lacks built-in cancellation support
Use Cases
Recommended for short-lived asynchronous operations
Better suited for long-running computations or unmanaged code

QnA

What is the difference between string keyword and System.String class?

there is no difference. The string keyword is an alias for System.String class.

Are string objects mutable or immutable?

String objects are immutable. All of the String methods and C# operators that appear to modify a string actually return the results in a new string object.

What is a verbatim string literal and why do we use it?

The “@” symbol is the verbatim string literal. Use verbatim strings for convenience and better readability when the string text contains backslash characters, for example in file paths.
string ImagePath = @"C:\Images\Buttons\SaveButton.jpg"; //Output: C:\Images\Buttons\SaveButton.jpg string MultiLineText = @"This is multiline Text written to be in three lines."; /* Output: This is multiline Text written to be in three lines. */ string DoubleQuotesString = @"My Name is ""Pranaya."""; //Output: My Name is "Pranaya."

What is the difference between System.Text.StringBuilder and System.String?

This is one of the frequently asked C#.NET Interview Questions. Objects of type StringBuilder are mutable whereas objects of type System.String is immutable. As StringBuilder objects are mutable, they offer better performance than string objects of type System.String.

Difference between int and Int32 in C#

Int32 and int are synonymous, both of them allow us to create a 32-bit integer. int is shorthand notation (alias) for Int32.

What's the limit on stack to store value types

There are a few key limits related to storing value types on the stack in C#:
  1. Stack size: The default stack size for a 32-bit process in .NET is 1 MB, and for a 64-bit process it is 4 MB. This limits the total amount of memory that can be allocated on the stack.
  1. Maximum stack allocation size: While the stack size is 1 MB or 4 MB, the maximum size of a single stack allocation is lower. The exact limit depends on the specific version of .NET, but is typically around 1-2 MB. Trying to allocate more than this will result in a StackOverflowException.
  1. Numeric type limits: There are maximum and minimum values defined for each numeric value type in C#, based on the number of bits they use:
      • sbyte: -128 to 127
      • byte: 0 to 255
      • short: -32,768 to 32,767
      • ushort: 0 to 65,535
      • int: -2,147,483,648 to 2,147,483,647
      • uint: 0 to 4,294,967,295
      • long: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
      • ulong: 0 to 18,446,744,073,709,551,615
  1. Maximum string length: The maximum length of a string in C# is Int32.MaxValue, which is 2,147,483,647 characters. This limit is imposed by the .NET runtime due to memory constraints.

What are Access Modifiers in C#?

  1. Public: The public type or member can be accessed by any other code in the same assembly or another assembly that references it.
  1. Private: The type or member can only be accessed by code in the same class or struct.
  1. Protected: The type or member can only be accessed by code in the same class or struct, or in a derived class.
  1. Internal: The type or member can be accessed by any code in the same assembly, but not from another assembly.
  1. Protected Internal: The type or member can be accessed by any code in the same assembly, or by any derived class in another assembly.

What is CLR

Common language runtime (CLR). The CLR manages the life cycle and executes .NET applications (code). It also provides services that make the development process easier.
The runtime provides the following benefits:
  • Performance improvements.
  • Language features such as inheritance, interfaces, and overloading for object-oriented programming.
  • Garbage collection.
  • Use of delegates instead of function pointers for increased type safety and security.

What is CTS?

Languages including Common Type System (CTS) and Common Language Specification (CLS) that define the specifications of how types are defined and works is another major component of .NET.
notion image

What is the difference between a Queue and a Stack in .NET

Queue and stack are two common implementations when creating linked lists. A queue uses the first-in-first-out algorithm. The stack uses a last-in-first-out algorithm. Both are generic collections in C# and .NET.

What is the purpose of Generics in .NET

Generics in C# and .NET procedure many of the benefits of strongly-typed collections as well as provide a higher quality of and a performance boost for code. .NET Generics are not limited to classes only. In fact they can also be implemented with Interfaces, Delegates and Methods.
class DataStore<T> { public T Data {get; set;} } DataStore<string> store = new DataStore<string>();

What is the difference between Deep Copy and Shallow Copy?

When implementing copy constructors, it's essential to understand the difference between shallow and deep copies:
  • Shallow Copy: A shallow copy creates a new object, but the fields of the new object reference the same memory locations as the original object. Changes to reference-type fields in the new object will affect the original object.
  • Deep Copy: A deep copy creates a new object and recursively copies all the fields of the original object, including any referenced objects. The new object is entirely independent of the original.

What's the use of copy constructor

A copy constructor in C# is a special type of constructor that initializes a new object as a copy of an existing object. It is particularly useful when you want to create a duplicate of an object while ensuring that the new object has the same state as the original. This concept is essential in scenarios where you need to manage mutable objects, allowing modifications to the new object without affecting the original.

Key Uses of Copy Constructors

  1. Object Duplication: Copy constructors allow you to create a new object that is a copy of an existing object. This is useful when you need to duplicate the state of an object for further processing without altering the original object.
  1. Avoiding Side Effects: When working with mutable objects, changes made to the copied object should not affect the original object. A copy constructor ensures that the new object is independent of the original.
  1. Encapsulation: By using a copy constructor, you can maintain proper encapsulation, avoiding direct manipulation of an object's internal state from outside the class.
  1. Passing Objects by Value: When passing objects to methods, using a copy constructor can help ensure that the method works with a copy rather than the original object, preventing unintended modifications.

What's a private constructor?

A private constructor in C# is a special instance constructor that is declared with the ‘private’ access modifier. It can only be called within the class itself and is often used for specific purposes, such as implementing design patterns like the Singleton pattern or providing controlled instance creation.Key points about private constructors:
  1. Prevents external instantiation: Since a private constructor can only be accessed within the class, it prevents the creation of instances of the class from outside the class.
  1. Used with static members: Private constructors are commonly used in classes that contain static members only. These classes are not meant to be instantiated.
  1. Singleton pattern implementation: Private constructors are essential for implementing the Singleton pattern, which ensures that a class has only one instance.
  1. Prevents automatic default constructor generation: If a class has only private constructors (with no parameters), the compiler will not generate a default constructor automatically.
  1. Nested classes can access private constructors: While other classes cannot create instances of a class with a private constructor, nested classes can access the private constructor.
Here's an example of a private constructor:
public class Singleton { private static Singleton instance = null; private Singleton() { *// Private constructor to prevent external instantiation* } public static Singleton GetInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }`

What’s the difference b/w a class with private constructor and static class?

Key Differences
Instantiation:
  • A static class cannot be instantiated at all.
  • A class with a private constructor cannot be instantiated from outside the class but can have instances created through controlled means (like a singleton).
Members:
  • A static class can only contain static members.
  • A class with a private constructor can contain both static and instance members.
Inheritance:
  • Static classes cannot be inherited.
  • A class with a private constructor can be inherited by nested classes.

Can “this” be used within a Static Method?

  • No, “this” cannot be used within a static method.
  • Because the keyword 'this' returns a reference to the current instance of the class containing it.

What is the use of the Yield keyword in C#?

The yield keyword in C# is used to simplify the creation of iterator blocks, allowing for custom iteration over collections. It enables methods to return an
IEnumerable or IEnumerator without the need to create a temporary collection to hold the results. Here’s a summary of its uses based on the search results:

Uses of the yield Keyword

  1. Iterator Blocks: The yield keyword informs the compiler that the method in which it appears is an iterator block. This allows the method to return values one at a time, preserving the state between calls.
  1. yield return: This statement is used to return the next value in the iteration. Each time the yield return statement is executed, the current location in the code is saved, and execution is paused until the next iteration is requested.
      • Example:
        • public static IEnumerable<int> GetNumbers() { for (int i = 0; i < 5; i++) { yield return i; // Returns the current value of i } }
  1. yield break: This statement is used to terminate the iteration. It signals that there are no more values to return, effectively ending the iteration early.
      • Example:
        • public static IEnumerable<int> GetPositiveNumbers(IEnumerable<int> numbers) { foreach (int number in numbers) { if (number < 0) yield break; // Stops iteration if a negative number is encountered yield return number; // Returns positive numbers } }
  1. Lazy Evaluation: The yield keyword allows for lazy evaluation of collections. This means that values are generated on-the-fly as they are requested, rather than being computed and stored all at once. This can lead to improved performance and reduced memory usage.
  1. Stateful Iteration: With yield, you can maintain state across iterations without needing to manage the state explicitly. This makes it easier to create complex iteration logic.

What is a base keyword?

  • 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.
  • It is an error to use the base keyword from within a static method.