Ticker

6/recent/ticker-posts

Header Ads Widget

The Essential C#/.NET Handbook # 48 - 60

 

The Essential C#/.NET Handbook # 48 - 60 - C-Sharp Encyclopedia of Notions

48. protected

    A protected member is accessible within the same class and derived classes but not from outside classes.

Example:

class Parent {

    protected int data = 42;

}

 

class Child : Parent {

    public void ShowData() {

        Console.WriteLine(data);  // Allowed

    }

}

This is useful for inheritance, allowing derived classes to use certain members without exposing them globally.

49. internal

    An internal member is accessible only within the same assembly (project) but not from another project that references it.

Example:

internal class InternalClass {

    public void Method() { }

}

Useful for defining APIs within an application while preventing external access.

50. protected internal

    A protected internal member is accessible within the same assembly OR from derived classes (even in different assemblies).

Example:

protected internal int value;

This provides a mix of protected and internal access, useful in libraries where subclasses need access but not unrelated classes.

51. private protected

    A private protected member is accessible only within the same assembly AND from derived classes. This was introduced in C# 7.2 for tighter access control.

Example:

class Parent {

    private protected int data = 10;

}

Only derived classes inside the same assembly can access it.

52. sealed override

    A sealed override prevents further overriding of a virtual method.

Example:

class Base {

    public virtual void Show() { }

}

 

class Derived : Base {

    public sealed override void Show() { }

}

Any class that extends Derived cannot override Show(). This is useful when you want to override a base method once but prevent further changes.

53. static constructor

    A static constructor initializes static members of a class and executes only once when the class is first used. It has no parameters and cannot be called manually.

Example:

class Example {

    static Example() {

        Console.WriteLine("Static constructor executed");

    }

}

Used to initialize static fields or perform one-time setup before any instance is created.

54. constant

    A constant in C# is a value that is declared at compile-time and remains unchanged throughout the program's execution. It is defined using the const keyword and must be assigned at the time of declaration. Once set, it cannot be modified later, making it ideal for fixed values like mathematical constants, configuration settings, or predefined strings.

Example:

class Example {

    public const double Pi = 3.14159;

}

Here, Pi is a constant and cannot be changed anywhere in the program.

Key Features:

  • Stored in memory at compile time.
  • Faster than variables because the compiler replaces them with their actual value.
  • Cannot hold objects or reference types, except for string.
  • Scope can be public, private, protected, etc.

Limitations:

  • Cannot be assigned at runtime (e.g., values from user input or configuration files).
  • Cannot hold instance-specific data—only static or global values.
  • Any change requires recompilation of the entire program, which can be problematic for configurable settings.

Constants are useful for fixed values but should be used sparingly when flexibility is required.

 

55. readonly

    A readonly field is a special type of variable that can be assigned only once after declaration, either at the time of declaration or inside a constructor. Unlike const, it can be initialized at runtime, making it useful for values that must be set once but can depend on input, configuration, or instance-specific data.

Example:

class Example {

    public readonly int InstanceID;

 

    public Example(int id) {

        InstanceID = id;  // Allowed inside constructor

    }

}

Here, InstanceID can be assigned a value when an object is created, but after that, it cannot be modified.

Key Features:

  • Can store instance-specific values.
  • Works with both value types and reference types (unlike const).
  • Allows initialization at declaration or within a constructor.

Differences from const:

  • readonly fields can be initialized at runtime; const must be assigned at compile-time.
  • readonly supports objects and reference types, whereas const does not.

Use readonly when a value should not change after initialization but depends on external factors (e.g., configuration settings or runtime calculations).

 

56. var keyword

    The var keyword enables type inference, meaning the compiler automatically determines the type of a variable based on the assigned value. It makes code more concise and readable without sacrificing type safety.

Example:

var number = 10;        // Compiler infers int

var name = "Szabi";     // Compiler infers string

var list = new List<int>(); // Compiler infers List<int>

Despite using var, the compiler still enforces strong typing—once a type is inferred, it cannot be changed later.

Advantages:

  • Less typing, better readability, especially when working with complex types like dictionaries or generics.
  • Ensures type safety, unlike dynamic.
  • Helps in anonymous types, where explicit declaration is impossible.

Limitations:

  • Cannot be used for class fields or method parameters (only for local variables).
  • Reduces explicit type clarity—can be harder to read when overused.

Use var for concise, readable code but avoid excessive use when clarity is needed.

 

57. dynamic keyword

    The dynamic keyword allows runtime type resolution, meaning the compiler defers type checking until the program runs. Unlike var, which infers a fixed type at compile time, dynamic variables can change types at runtime.

Example:

dynamic value = 10;  // Initially an int

value = "Hello";     // Now a string

This flexibility makes dynamic useful in scenarios like reflection, COM interactions, or JSON deserialization.

Key Features:

  • No compile-time type checking—errors appear at runtime.
  • Supports dynamic method calls, meaning you can invoke methods that may not exist at compile time.
  • Used extensively in interoperability scenarios (e.g., Office COM objects, scripting engines).

Risks:

  • No IntelliSense support in IDEs because the compiler does not know the type.
  • Errors are discovered at runtime, making debugging harder.

Use dynamic only when necessary, especially in external API integrations or when working with unknown types.

 

58. in keyword

    The in keyword is used to pass parameters by reference while ensuring they cannot be modified within the method. It allows efficient passing of large structures without making a copy, improving performance in performance-critical applications.

Example:

void Print(in int number) {

    Console.WriteLine(number);

}

 

int value = 10;

Print(value);  // Allowed

// value = 20; // Error! Cannot modify inside the method

Key Features:

  • Improves performance by avoiding unnecessary copies of large objects.
  • Ensures read-only access within the method.
  • Works well with structs and value types to optimize memory usage.

Best used in scenarios where data should not be modified but needs efficient passing.

 

59. out keyword

    The out keyword is used to pass arguments by reference, ensuring the called method assigns a value before returning. It is commonly used for multiple return values.

Example:

void GetValues(out int x, out int y) {

    x = 10;

    y = 20;

}

 

int a, b;

GetValues(out a, out b);  // a = 10, b = 20

Key Features:

  • The method must assign a value before returning.
  • Allows returning multiple values from a function.
  • Often used with TryParse methods (e.g., int.TryParse).

Use out when a method needs to return multiple values without using tuples or objects.

 

60. ref keyword

    The ref keyword passes a parameter by reference, allowing both reading and writing of its value. Unlike out, it requires an initial value before being passed.

Example:

void Modify(ref int x) {

    x *= 2;

}

 

int num = 10;

Modify(ref num);  // num becomes 20

Key Features:

  • Allows modifying the original variable inside the method.
  • Must be initialized before passing (unlike out).
  • Useful in performance-sensitive applications to avoid copying large structures.

Use ref when a method needs to modify a variable while keeping its original reference.