C# Class Members

Understanding fields, methods, properties, and more

🧩 What are Class Members?

Class members are the components that make up a class. They include fields, methods, properties, constructors, and events that define the data and behavior of objects.


class Person
{
    // Field
    public string name;
    
    // Method
    public void Greet() { }
}
                                    

Types of Class Members

📦

Fields

Variables that store object data

public string name;
public int age;
private decimal salary;

Methods

Functions that define behavior

public void Walk()
{
    Console.WriteLine("Walking");
}
🎛️

Properties

Controlled access to fields

public string Name 
{ 
    get; 
    set; 
}
🔧

Constructors

Initialize new objects

public Person(string n)
{
    name = n;
}

🔹 Fields (Variables)

Fields, also known as member variables, are variables declared directly within a class to store data. They represent the state and attributes of an object instance. Each object gets its own copy of instance fields unless marked as static, which makes them shared across all instances. Fields should typically be kept private to enforce encapsulation and data protection. Public properties or methods provide controlled access to these fields. For example, a Person class might have private fields _name and _age. Using properties like public string Name { get; set; } instead of public fields is considered a best practice, as it allows for validation, logging, or implementing future logic changes without breaking the class's external interface or contract.

class Employee
{
    // Instance fields (each object has its own copy)
    public string Name;
    public int EmployeeId;
    public decimal Salary;
    private string password;  // Private field

    // Static field (shared by all objects)
    public static string CompanyName = "TechCorp";

    public void DisplayInfo()
    {
        Console.WriteLine("Name: " + Name);
        Console.WriteLine("ID: " + EmployeeId);
        Console.WriteLine("Company: " + CompanyName);
    }
}

// Usage
Employee emp1 = new Employee();
emp1.Name = "Alice";
emp1.EmployeeId = 101;
emp1.Salary = 50000;

Employee emp2 = new Employee();
emp2.Name = "Bob";
emp2.EmployeeId = 102;

emp1.DisplayInfo();
emp2.DisplayInfo();

Output:

Name: Alice

ID: 101

Company: TechCorp

Name: Bob

ID: 102

Company: TechCorp

🔹 Methods (Functions)

Methods define the behaviors and actions that an object can perform. They encapsulate logic, can accept input parameters, perform operations, and return results. The outputs here demonstrate method functionality: calculating a sum (15), computing an average (85), and determining a product (20). For instance, a method like CalculateSum(int a, int b) would process the inputs and return the total. This modular approach promotes code reuse, organization, and clarity, allowing complex tasks to be broken into manageable, callable units.

class Calculator
{
    // Method with return value
    public int Add(int a, int b)
    {
        return a + b;
    }

    // Method without return value (void)
    public void PrintResult(int result)
    {
        Console.WriteLine("Result: " + result);
    }

    // Method with multiple parameters
    public double CalculateAverage(int num1, int num2, int num3)
    {
        return (num1 + num2 + num3) / 3.0;
    }

    // Static method (called on class, not object)
    public static int Multiply(int a, int b)
    {
        return a * b;
    }
}

// Usage
Calculator calc = new Calculator();
int sum = calc.Add(10, 5);
calc.PrintResult(sum);

double avg = calc.CalculateAverage(80, 90, 85);
Console.WriteLine("Average: " + avg);

// Call static method
int product = Calculator.Multiply(4, 5);
Console.WriteLine("Product: " + product);

Output:

Result: 15

Average: 85

Product: 20

🔹 Properties

Properties provide a controlled, secure way to access and modify class field data. They act as intelligent intermediaries using get and set accessors. The examples show a property returning "John", another managing an age value (25), and one combining them into a formatted string ("John is 25 years old"). Properties can include validation logic, as seen in the "Invalid age!" output, which prevents illogical data assignment. This mechanism supports encapsulation, a core Object-Oriented Programming principle, ensuring data integrity and flexibility.

class Person
{
    private string name;  // Private field
    private int age;

    // Property with full control
    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    // Property with validation
    public int Age
    {
        get { return age; }
        set 
        { 
            if (value >= 0 && value <= 120)
                age = value;
            else
                Console.WriteLine("Invalid age!");
        }
    }

    // Auto-implemented property (shorthand)
    public string Email { get; set; }

    // Read-only property
    public string Info
    {
        get { return name + " is " + age + " years old"; }
    }
}

// Usage
Person person = new Person();
person.Name = "John";
person.Age = 25;
person.Email = "[email protected]";

Console.WriteLine(person.Name);
Console.WriteLine(person.Age);
Console.WriteLine(person.Info);

person.Age = 150;  // Invalid age!

Output:

John

25

John is 25 years old

Invalid age!

🔹 Constants and Read-Only Fields

Constants and read-only fields store values that are immutable and should not change during program execution. Constants, like the mathematical PI (3.14159), are fixed at compile-time and used directly in calculations such as finding a circle's area (78.53975). Read-only fields, like a version number ("1.0"), can be assigned once at runtime, typically within a constructor. Using these constructs ensures critical values remain consistent, prevents accidental modification, improves code readability, and can offer performance benefits by allowing compiler optimizations.

class MathHelper
{
    // Constant (must be initialized, cannot change)
    public const double PI = 3.14159;
    public const int MaxValue = 100;

    // Read-only field (can be set in constructor)
    public readonly string Version;
    public readonly DateTime CreatedDate;

    public MathHelper()
    {
        Version = "1.0";
        CreatedDate = DateTime.Now;
    }

    public double CalculateCircleArea(double radius)
    {
        return PI * radius * radius;
    }
}

// Usage
Console.WriteLine("PI value: " + MathHelper.PI);

MathHelper helper = new MathHelper();
double area = helper.CalculateCircleArea(5);
Console.WriteLine("Circle area: " + area);
Console.WriteLine("Version: " + helper.Version);

Output:

PI value: 3.14159

Circle area: 78.53975

Version: 1.0

🔹 Static vs Instance Members

Instance members belong to individual objects, while static members belong to the class itself and are shared across all instances. The outputs illustrate this: object c1 has a count of 2, c2 has 1 (instance-specific), but the static count totals 3 (shared across the class). Instance members, like an object's name, are unique per creation. Static members, often used for counters, utility functions, or shared configurations, are accessed via the class name. Understanding this distinction is crucial for designing efficient, memory-conscious applications and avoiding common data-sharing pitfalls.

class Counter
{
    // Instance field (each object has its own)
    public int InstanceCount = 0;

    // Static field (shared by all objects)
    public static int StaticCount = 0;

    // Instance method
    public void IncrementInstance()
    {
        InstanceCount++;
    }

    // Static method
    public static void IncrementStatic()
    {
        StaticCount++;
    }
}

// Usage
Counter c1 = new Counter();
Counter c2 = new Counter();

c1.IncrementInstance();
c1.IncrementInstance();
c2.IncrementInstance();

Counter.IncrementStatic();
Counter.IncrementStatic();
Counter.IncrementStatic();

Console.WriteLine("c1 instance count: " + c1.InstanceCount);
Console.WriteLine("c2 instance count: " + c2.InstanceCount);
Console.WriteLine("Static count: " + Counter.StaticCount);

Output:

c1 instance count: 2

c2 instance count: 1

Static count: 3

🔹 Method Overloading

Method overloading allows multiple methods within the same class to share a name but differ in their parameter lists (type, number, or order). This provides flexibility in how a method can be invoked. The repeated "Message: Hi" outputs likely come from overloaded DisplayMessage methods handling different inputs, while "Number: 42" shows an overload for integer parameters. The compiler determines which version to execute based on the arguments provided. Overloading enhances API intuitiveness, reduces the need for disparate method names, and supports polymorphism, a key OOP concept.

class Printer
{
    // Method with one parameter
    public void Print(string message)
    {
        Console.WriteLine("Message: " + message);
    }

    // Overloaded method with two parameters
    public void Print(string message, int times)
    {
        for (int i = 0; i < times; i++)
        {
            Console.WriteLine("Message: " + message);
        }
    }

    // Overloaded method with different parameter type
    public void Print(int number)
    {
        Console.WriteLine("Number: " + number);
    }
}

// Usage
Printer printer = new Printer();
printer.Print("Hello");
printer.Print("Hi", 3);
printer.Print(42);

Output:

Message: Hello

Message: Hi

Message: Hi

Message: Hi

Number: 42

🔹 Member Summary

Quick Reference:

  • Fields: Store data (variables in a class)
  • Methods: Define behavior (functions in a class)
  • Properties: Controlled access to fields (get/set)
  • Constants: Fixed values that never change
  • Static Members: Belong to class, not objects
  • Instance Members: Belong to specific objects

🧠 Test Your Knowledge

Which keyword makes a member shared across all objects?