C# and .NET Framework Core Concepts Q&A
Garbage Collection Importance and .NET Architecture
Importance of Garbage Collection (GC) in .NET
Garbage Collection (GC) is an automatic memory management feature in the .NET Framework that plays a crucial role in improving application performance and memory efficiency. Its importance includes:
- Automatic Memory Management: Developers do not need to manually allocate or deallocate memory, reducing complexity and potential errors.
- Improved Application Performance: By efficiently reclaiming unused memory, GC ensures resources are available for active processes.
- Object Lifetime Tracking: GC automatically tracks which objects are still reachable and which are eligible for collection.
- Prevents Memory Leaks: It automatically cleans up objects that are no longer referenced, preventing common memory leak issues.
- Efficient Memory Usage: It compacts the heap, reducing fragmentation and making better use of available memory space.
.NET Framework Architecture
The .NET Framework is a platform for building and running Windows applications. It consists primarily of the Common Language Runtime (CLR) and a rich set of Class Libraries.
1. .NET Applications
These are user-developed applications (like Web, Desktop, Console applications) that run on top of the .NET Framework.
2. Base Class Library (BCL)
The BCL provides a large set of pre-built reusable classes. This includes libraries for file I/O, networking, collections, databases, and more.
3. Common Language Runtime (CLR)
The CLR is the execution engine of the .NET Framework. Key components include:
- Garbage Collector (GC): Manages memory and object lifetime.
- JIT Compiler: Converts MSIL (Microsoft Intermediate Language) to native machine code at runtime.
Jagged Arrays and C# Multidimensional Array Example
What is a Variable Size Array?
A Variable Size Array (also called a jagged array) in C# is an array whose elements are arrays of different sizes. This allows you to store data in a non-uniform (ragged) format.
C# Program: Multidimensional Array for Student Marks
The following program creates a standard multidimensional array (not a jagged array) to store the marks of three students in four subjects:
using System;
class Program
{
static void Main()
{
int[,] marks = new int[3, 4];
for (int student = 0; student < 3; student++)
{
Console.WriteLine($"Enter marks for Student {student + 1}:");
for (int subject = 0; subject < 4; subject++)
{
Console.Write($"Subject {subject + 1}: ");
marks[student, subject] = Convert.ToInt32(Console.ReadLine());
}
}
Console.WriteLine("\nMarks of all students:");
for (int student = 0; student < 3; student++)
{
Console.Write($"Student {student + 1}: ");
for (int subject = 0; subject < 4; subject++)
{
Console.Write(marks[student, subject] + " ");
}
Console.WriteLine();
}
}
}
C# LINQ Query for Selecting Odd and Even Numbers
This C# program uses LINQ (Language Integrated Query) query syntax to separate odd and even numbers from a list ranging from 1 to 30.
using System;
using System.Linq;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<int> numbers = Enumerable.Range(1, 30).ToList();
// LINQ Query for Even Numbers
var evenNumbers = from num in numbers
where num % 2 == 0
select num;
// LINQ Query for Odd Numbers
var oddNumbers = from num in numbers
where num % 2 != 0
select num;
Console.WriteLine("Even Numbers (1 to 30):");
foreach (var num in evenNumbers)
{
Console.Write(num + " ");
}
Console.WriteLine("\n\nOdd Numbers (1 to 30):");
foreach (var num in oddNumbers)
{
Console.Write(num + " ");
}
}
}
Static Classes and Constructors in C#
Static Class Concept
A static class in C# is a class that:
- Cannot be instantiated: You cannot create objects from it using the
new
keyword. - Can only contain static members (methods, fields, properties).
- Is used when the class is only meant to provide helper methods or global utility functions (e.g.,
System.Math
).
Static Constructor Concept
A static constructor:
- Is used to initialize static data or perform actions that need to be done only once per application domain.
- Is called automatically before the first instance is created or before any static members are referenced.
- Has no parameters and no access modifiers.
C# Program Example
using System;
static class MathHelper
{
public static int Factor;
static MathHelper()
{
Console.WriteLine("Static Constructor Called");
Factor = 10;
}
public static int Multiply(int x)
{
return x * Factor;
}
}
class Program
{
static void Main()
{
Console.WriteLine("Main Started");
// Accessing a static member triggers the static constructor
int result = MathHelper.Multiply(5);
Console.WriteLine("Result: " + result);
}
}
Named Arguments and Namespace Aliasing in C#
Named Arguments
A named argument in C# allows you to pass arguments to a method by specifying the parameter name, regardless of their position. Benefits include:
- Improves code readability, especially for methods with many parameters.
- Allows skipping optional parameters easily.
Alias for Namespace in C#
Sometimes two namespaces may have the same class names, causing conflicts. To resolve this, we can use a namespace alias, which provides a shorter or unique name for a namespace.
C# Program: Namespace Aliasing
using System;
using Project1 = System.Collections.Generic;
using Project2 = System.Text;
class Program
{
static void Main()
{
Project1.List<string> names = new Project1.List<string>();
names.Add("Aliasing example");
Project2.StringBuilder sb = new Project2.StringBuilder();
sb.Append("Hello from alias!");
Console.WriteLine(names[0]);
Console.WriteLine(sb.ToString());
}
}
Static Binding and Binary Operator Overloading in C#
Static Binding (Early Binding)
Static Binding means the method call is resolved at compile time. It occurs with:
- Non-virtual methods.
- Overloaded methods.
- Calls to static or private methods.
C# Program: Binary Operator Overloading (Complex Numbers)
This program demonstrates overloading the binary +
and -
operators to handle complex number arithmetic.
using System;
class Complex
{
public int Real;
public int Imag;
public Complex(int r, int i)
{
Real = r;
Imag = i;
}
// Overloading the addition operator
public static Complex operator +(Complex c1, Complex c2)
{
return new Complex(c1.Real + c2.Real, c1.Imag + c2.Imag);
}
// Overloading the subtraction operator
public static Complex operator -(Complex c1, Complex c2)
{
return new Complex(c1.Real - c2.Real, c1.Imag - c2.Imag);
}
public void Display()
{
Console.WriteLine($"{Real} + {Imag}i");
}
}
class Program
{
static void Main()
{
Complex c1 = new Complex(5, 4);
Complex c2 = new Complex(2, 3);
Complex sum = c1 + c2;
Complex diff = c1 - c2;
Console.Write("Sum: ");
sum.Display();
Console.Write("Difference: ");
diff.Display();
}
}
Purpose and Use Cases of Delegates in C#
A delegate is a type that represents references to methods with a specific signature. It is like a type-safe function pointer in C/C++.
Key Purposes of Delegates
- Callback Mechanism: Allows calling methods passed as parameters.
- Event Handling: Used extensively with events in .NET (e.g., handling a button click).
- Encapsulation: Encapsulates method(s) to be called dynamically.
- Multicasting: A delegate can hold references to multiple methods and call them sequentially (multicast delegate).
C# Concepts: Copy Constructor, Indexer, Lambda
a) Copy Constructor
A copy constructor is a special constructor in a class used to create a new object as a copy of an existing object.
- Takes an object of the same class as a parameter.
- Performs deep or shallow copying of fields.
class Student
{
public string Name;
// Copy Constructor
public Student(Student s)
{
Name = s.Name;
}
}
b) Indexer in C#
An indexer allows a class or struct to be accessed like an array using the [ ]
brackets.
- Defined using the
this
keyword. - Can include
get
,set
, or both accessors. - Makes an object behave like a collection.
class Sample
{
private int[] data = new int[5];
public int this[int index]
{
get { return data[index]; }
set { data[index] = value; }
}
}
c) Lambda Expression in C#
A lambda expression is a concise way to represent anonymous methods using the =>
operator.
Syntax:
(parameters) => expression_or_statement_block
Func<int, int> square = x => x * x;
// Console.WriteLine(square(5)); // Output: 25
Use Cases: LINQ queries, delegates and events, and anonymous function calls.
Definition and Features of Managed Code in .NET
Managed Code is the code that is executed and managed by the Common Language Runtime (CLR) in the .NET framework.
Features of Managed Code
- The CLR manages memory allocation, garbage collection, and security.
- Provides type safety, ensuring that code accesses memory only in authorized ways.
- Includes built-in exception handling mechanisms.
- Enables cross-language interoperability.
Optional Parameters and Enumerations in C#
Optional Parameters
Optional parameters allow you to omit arguments in a method call. They must be assigned default values if not provided.
Syntax Example:
void Display(string name = "Default") { }
C# Program: Storing Values in Enumerations
using System;
enum Department { Computer, Physics, Mathematics, Management }
enum College { Science, Commerce, Arts }
class Program
{
static void Main()
{
Department dept = Department.Computer;
College college = College.Science;
Console.WriteLine("Department: " + dept);
Console.WriteLine("College: " + college);
}
}
Value Types vs. Reference Types in C#
The primary difference lies in where the data is stored and how variables handle assignment and equality.
Reference Types
- Storage: Stored on the heap. The variable holds a reference (memory address) to the object location.
- Copying: Copying creates a new reference pointing to the same object instance.
- Equality: Determined by reference (do they point to the same memory location?), unless overridden.
- Inheritance: Reference types can inherit from other classes.
- Performance: May have a performance overhead due to heap allocation and garbage collection.
Value Types
- Storage: Stored on the stack (or inline within a reference type). The variable stores the value itself directly.
- Copying: Copying creates a new instance with its own copy of the value (deep copy).
- Equality: Determined by value (do they contain the same data?).
- Inheritance: Value types cannot inherit from other types (they implicitly inherit from
System.ValueType
). - Performance: Generally have a smaller memory footprint and can be more performant for small data structures.
Interfaces and Achieving Multiple Inheritance in C#
What is an Interface?
An interface is a contract that defines method signatures, properties, events, or indexers without providing implementation. Classes or structs that implement the interface must provide the implementation for all its members.
Use Cases for Interfaces
- Defining common behavior for different classes.
- Achieving multiple inheritance of behavior (since C# does not support multiple inheritance of classes).
C# Program: Multiple Inheritance via Interfaces
using System;
interface IAnimal
{
void Speak();
}
interface IPet
{
void Play();
}
// A class can implement multiple interfaces
class Dog : IAnimal, IPet
{
public void Speak()
{
Console.WriteLine("Dog barks");
}
public void Play()
{
Console.WriteLine("Dog plays fetch");
}
}
class Program
{
static void Main()
{
Dog d = new Dog();
d.Speak();
d.Play();
}
}
The Role of Finalize() Method in C# Cleanup
The Finalize()
method (implemented via the destructor syntax ~ClassName()
) is used to perform cleanup operations on unmanaged resources before an object is reclaimed by the Garbage Collector (GC).
Key Points
- It is automatically called by the GC, not explicitly by the user.
- It is declared using destructor syntax:
~ClassName()
. - Its execution is non-deterministic and should only be used for releasing unmanaged resources. For deterministic cleanup,
IDisposable
should be used.
Example: Destructor Syntax
class Demo
{
~Demo()
{
Console.WriteLine("Finalize called.");
}
}
C# Exception Handling Keywords and Examples
Keywords Used in Exception Handling
try
: Block of code to monitor for potential exceptions.catch
: Handles the exception if one occurs in thetry
block.finally
: Executes regardless of whether an exception occurred or was handled.throw
: Manually throws an exception.
C# Program: Handling Specific Exceptions
This program demonstrates handling IndexOutOfRangeException
and InvalidCastException
.
using System;
class Program
{
static void Main()
{
try
{
int[] arr = new int[3];
// 1. IndexOutOfRangeException
Console.WriteLine(arr[5]);
// 2. InvalidCastException
object obj = "Hello";
int num = (int)obj;
}
catch (IndexOutOfRangeException e)
{
Console.WriteLine("Index Error: " + e.Message);
}
catch (InvalidCastException e)
{
Console.WriteLine("Cast Error: " + e.Message);
}
finally
{
Console.WriteLine("Finally block executed.");
}
}
}
LINQ Query Syntax and Standard Operators
LINQ Query Syntax
Query Syntax is a declarative, SQL-like syntax used in LINQ (Language Integrated Query) to query collections (like arrays, lists, or databases).
Basic Structure:
from variable in collection
where condition
orderby variable
select variable;
Standard Query Operators in LINQ
select
: Projects (transforms) the elements of a sequence into a new form.where
: Filters a sequence based on a specified condition.orderBy
: Sorts the elements of a sequence in ascending or descending order.Contains
: (Method Syntax) Checks if an element exists in the collection.
C# Program: LINQ Operators Example
using System;
using System.Linq;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<int> numbers = new List<int> { 5, 10, 15, 20, 25 };
// Using where, orderby, and select (Query Syntax)
var result = from n in numbers
where n > 10
orderby n
select n;
Console.WriteLine("Numbers > 10 (Ordered):");
foreach (var num in result)
{
Console.WriteLine(num);
}
// Using Contains (Method Syntax)
bool hasTwenty = numbers.Contains(20);
Console.WriteLine("\nList contains 20? " + hasTwenty);
}
}
Lambda Expressions: Definition and Types
A lambda expression is an anonymous function used to create delegates or expression tree types concisely.
Lambda Expression Types
Expression Lambda
Used when the body consists of a single expression that returns a value. The compiler infers the return type.
// Example: Takes x, returns x * x Func<int, int> square = x => x * x;
Statement Lambda
Used when the body requires multiple statements. The statements must be enclosed in curly braces
{}
.// Example: Performs an action and returns a value Func<int, int> calculate = x => { int temp = x + 10; return temp * 2; };
Lambda with Parameters
Lambdas can take zero, one, or multiple parameters. Parentheses are optional for a single parameter but required for zero or multiple parameters.
// Zero parameters Action hello = () => Console.WriteLine("Hello"); // Multiple parameters Func<int, int, int> add = (a, b) => a + b;