Properties In C# Complete Guide

 Last Update:2025-06-23T00:00:00     .NET School AI Teacher - SELECT ANY TEXT TO EXPLANATION.    9 mins read      Difficulty-Level: beginner

Understanding the Core Concepts of Properties in C#

Properties in C# Explained in Detail

Importance of Properties:

  1. Encapsulation: Properties allow you to hide the internal representation of your objects, enforcing access rules and protecting the integrity of your data.
  2. Validation: You can add validation logic inside the property's setter to ensure that only valid data is set.
  3. Read-Only/Write-Only Access: By implementing only one of the accessor methods (get or set), properties can offer read-only or write-only access to fields.
  4. Computed Values: Properties can be used to compute values on-the-fly whenever they are accessed.

Basic Syntax:

A simple property consists of a private field and a property with public accessors get and set.

public class Person
{
    private string name;

    public string Name
    {
        get { return name; }
        set { name = value; }
    }
}

In this example, Person has a private field name. The Name property exposes this field with a get accessor that returns the value of name, and a set accessor that assigns a new value to name.

Auto-Implemented Properties:

For simple scenarios where no additional logic is required, C# provides auto-implemented properties, which automatically generate a hidden backing field.

public class Person
{
    public string Name { get; set; }
}

Here, the compiler generates a private field for Name, so you don't need to define it explicitly.

Accessors:

  • Get Accessor: Returns the current value of the property.

    public int Age
    {
        get { return age; }
    }
    
  • Set Accessor: Sets a new value to the property. The value keyword represents the new value being assigned.

    public int Age
    {
        set 
        { 
            if (value > 0) 
            {
                age = value;
            }
        }
    }
    

Combining both get and set accessors:

public int Age
{
    get { return age; }
    set 
    { 
        if (value > 0) 
        {
            age = value;
        }
    }
}

Expression-Bodied Properties:

C# also supports expression-bodied properties, providing a more concise syntax:

public string Name => name;
public string FullName => $"{FirstName} {LastName}";

And for setters:

public string Name 
{ 
    set => name = value; 
}

Read-Only and Write-Only Properties:

By including only one accessor, you can create a read-only or write-only property.

Read-Only Property:

public string ReadOnlyProperty 
{ 
    get => readOnlyField; 
}

Write-Only Property:

public int WriteOnlyProperty 
{ 
    set => writeOnlyField = value; 
}

However, note that true write-only properties are less common due to their limited utility.

Indexed Properties:

Indexed properties allow you to access elements within an object using an indexer, similar to arrays.

public class DaysOfTheWeek
{
    private string[] days;
    
    public DaysOfTheWeek()
    {
        days = new string[] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
    }

    public string this[int index]
    {
        get { return days[index]; }
        set { days[index] = value; }
    }
}

Usage:

DaysOfTheWeek d = new DaysOfTheWeek();
Console.WriteLine(d[0]); // Output: Sunday
d[0] = "NewDay";
Console.WriteLine(d[0]); // Output: NewDay

Property Modifiers:

You can use different modifiers to change the accessibility of properties and their accessors:

  • Public/Private/Protected/Internal: Determines the overall accessibility of the property.

    public class Example
    {
        private int _hiddenValue;
    
        public int HiddenValue
        {
            get { return _hiddenValue; }
            private set { _hiddenValue = value; } // Set accessor is private
        }
    }
    
  • Static: Shared across all instances of a class.

    public class Constants
    {
        public static int DefaultSize { get; } = 10;
    }
    

Customizing Accessors:

Properties can have custom accessors to add behaviors like logging, validation, or computations.

public class Circle
{
    private double radius;

    public double Radius
    {
        get 
        {
            // Additional behavior here
            Console.WriteLine("Getting radius...");
            return radius;
        }

        set 
        {
            // Validation logic
            if (value >= 0)
            {
                radius = value;
            }
            else 
            {
                throw new ArgumentException("Radius cannot be negative");
            }
        }
    }
}

Abstract and Virtual Properties:

Properties can also be defined as abstract in an abstract class, or virtual in a base class to be overridden in derived classes.

Abstract Property:

public abstract class Shape
{
    public abstract double Area { get; }
}

Virtual Property:

public class BaseClass
{
    public virtual string Description { get; set; } = "This is a base class";
}

public class DerivedClass : BaseClass
{
    public override string Description 
    { 
        get => "This is a derived class";
        set => base.Description = value; 
    }
}

Sealed Properties:

In a derived class, you can use the sealed modifier to prevent further overriding of a virtual or override property.

public class SealedDerivedClass : DerivedClass
{
    public sealed override string Description { get; set; }
}

Implementing Interface Properties:

When a class implements an interface, it must provide implementations for all the interface's properties.

public interface IEntity
{
    string Name { get; set; }
}

public class Customer : IEntity
{
    public string Name { get; set; }
}

Properties vs. Fields

Fields store data directly within an object, whereas properties define how data is accessed and modified. Using properties is generally preferred as they offer more control over the data.

Best Practices:

  1. Avoid Public Fields: Use properties instead of public fields to provide encapsulation and allow validation, logging, and other features.
  2. Use Proper Naming Conventions: Follow PascalCase for property names.
  3. Initialize Properties Properly: Use constructors or auto-implemented properties with initializers to establish default values.
  4. Document Properties: Provide XML comments to describe the purpose and usage of each property.

Summary:

Properties in C# are a powerful feature that provides controlled access to fields with flexibility in implementation. They enhance encapsulation, support validation, computed values, and can have custom behaviors in getters and setters. Understanding and utilizing properties effectively can lead to cleaner, more robust, and maintainable code.

Keywords (699 characters):

properties, c#, accessors, get, set, encapsulation, validation, private, fields, readable, writable, computed, values, security, maintainability, auto-implemented, expression-bodied, indexed, readonly, writeonly, static, abstract, virtual, sealed, interfaces, constructors, initialization, documentation, best, practices, naming, conventions, xml, comments, data, abstraction, control, flexible, methods, constructors, initializer, inheritance, overrides, security, maintainability, readability, writability, computation, flexible, controlled, access, robust, flexible, behaviors, initialization, encapsulate, data, protect, integrity, object-oriented, programming, design, patterns, class, members, flexible, implementation, control, security, maintainability, initialization, flexibility, robustness, encapsulated, data, protected, computation, object, oriented, programming, design, patterns, flexible, methods, behaviors, accessors, readonly, writeonly, fields, constructors, initialization, best, practices, encapsulation, validation, security, maintainability, abstraction, computation, flexibility, robustness, documentation, naming, conventions, xml, comments, class, members, interfaces, implementation, control, data, object-oriented, programming, design, patterns, constructors, initialization, best, practices, encapsulation, validation, security, maintainability, abstraction, computation, flexibility, robustness, documentation, class, members, interfaces, programming, design, patterns, constructors, initialization, best, practices, encapsulation, validation, security, maintainability, abstraction, computation, flexibility, design, patterns, constructors, initialization, best, practices, encapsulation, validation, security, maintainability, abstraction, computation, flexibility, robustness, documentation, class, members, interfaces, constructor, initialization, best, practices, encapsulation, validation, security, maintainability, abstraction, computation, flexibility, robustness, design, patterns, class, members, initialization, best, practices, encapsulation, validation, security, maintainability, abstraction, computation, flexible, robustness, documentation, class, members, interfaces, constructor, best, practices, encapsulation, validation, security, maintainability, abstraction, computation, flexible, robustness, documentation, class, members, interfaces, constructor, best, practices, encapsulation, validation, security, maintainability, abstraction, computation, flexible, robustness, documentation, class

Online Code run

🔔 Note: Select your programming language to check or run code at

💻 Run Code Compiler

Step-by-Step Guide: How to Implement Properties in C#

Example 1: Basic Property

Let's start with a simple example where we create a class Person with a property Name.

using System;

class Person
{
    // Private field to store the name
    private string name;

    // Public property to read/write the name
    public string Name
    {
        get { return name; }      // Getter method
        set { name = value; }     // Setter method
    }
}

class Program
{
    static void Main(string[] args)
    {
        // Create an instance of Person
        Person person = new Person();

        // Set the Name property using the setter
        person.Name = "Alice";

        // Get the Name property using the getter
        Console.WriteLine("The person's name is: " + person.Name);
    }
}

Explanation:

  1. Private Field (name): This field is used to store the actual data.
  2. Public Property (Name): This exposes the name field to the outside world with getter and setter methods.
    • The get method returns the value of name.
    • The set method assigns a new value to name through the value keyword.
  3. Main Method:
    • We create an instance of Person.
    • Assign a value to Name (setter is called internally).
    • Print the value of Name (getter is called internally).

Example 2: Auto-Implemented Property

C# provides a simpler syntax known as auto-implemented properties when no additional logic is required for getting or setting a value.

using System;

// Define a class named Person
class Person
{
    // Auto-implemented Name property
    public string Name { get; set; }
}

// Program entry point
class Program
{
    static void Main(string[] args)
    {
        // Create a new Person object
        Person person = new Person();

        // Set the Name property
        person.Name = "Bob";

        // Get and print the Name property
        Console.WriteLine("The person's name is: " + person.Name);
    }
}

Explanation:

  1. Auto-Implemented Property (Name): By using { get; set; }, you allow the compiler to define the backing field automatically.
  2. Usage: Access and modify it similarly like in the previous example, but without manually writing the getter and setter methods.

Example 3: Readonly Property

Sometimes you might want to expose properties that can only be set once, typically during initialization.

using System;

class Book
{
    // Private field to store the title
    private string title;

    // Constructor initializes the title field
    public Book(string title)
    {
        this.title = title;
    }

    // Readonly Title property (can only be set via constructor)
    public string Title
    {
        get { return title; }     // Only getter is provided
    }
}

class Program
{
    static void Main(string[] args)
    {
        // Create a new Book object
        Book book = new Book("Effective C#");

        // Get and print the Title property
        Console.WriteLine("Book Title: " + book.Title);

        // Uncommenting the line below will cause a compile-time error because Title has no setter
        // book.Title = "New Title";
    }
}

Explanation:

  1. Title Property: Since there's no set accessor, the Title can only be assigned inside the constructor.

Example 4: Property with Validation Logic

This example demonstrates how to put validation logic within a property setter.

using System;

class Account
{
    // Private field to store balance
    private decimal balance;

    // Property to expose balance with validation logic
    public decimal Balance
    {
        get { return balance; }   // Getter method
        set 
        { 
            if (value < 0)
                throw new ArgumentOutOfRangeException(nameof(value), "Balance cannot be negative");
            balance = value; 
        }                       // Setter method with validation
    }
    
    // Constructor to initialize account balance
    public Account(decimal initialBalance)
    {
        Balance = initialBalance;
    }
}

class Program
{
    static void Main(string[] args)
    {
        // Create an account with valid balance
        Account account = new Account(100.5m);

        Console.WriteLine("Account balance is: " + account.Balance);

        try
        {
            // Try to set an invalid negative balance
            account.Balance = -50.25m;
        }
        catch (ArgumentOutOfRangeException ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}

Explanation:

  1. Validation Logic: Inside the Balance setter, we check if the assigned value is less than zero (0). If it is, we throw an exception.
  2. Constructor: When creating the Account object, the constructor sets the balance using the property which includes our validation logic.
  3. Try/Catch Block: In the Main() method, we use a try-catch block to handle potential exceptions thrown from setting an invalid balance.

Example 5: Computed Property

Properties can also compute their value based on other fields.

using System;

class Product
{
    // Private fields for price and discount percentage
    private decimal price;
    private decimal discountPercentage;

    // Property for price
    public decimal Price
    {
        get { return price; }
        set { price = value; }
    }

    // Property for discount percentage
    public decimal DiscountPercentage
    {
        get { return discountPercentage; }
        set { discountPercentage = value; }
    }

    // Computed property for discount amount
    public decimal DiscountAmount
    {
        get { return (Price * DiscountPercentage) / 100; }   // Calculated based on Price and DiscountPercentage
    }
}

class Program
{
    static void Main(string[] args)
    {
        // Create a product with specified price and discount percentage
        Product product = new Product();
        product.Price = 99.99m;
        product.DiscountPercentage = 10m;

        // Print the computed discount amount
        Console.WriteLine("Discount Amount: " + product.DiscountAmount);
    }
}

Explanation:

  1. Computed Property (DiscountAmount): This property calculates its value whenever it is accessed by multiplying the price and discountPercentage, then dividing by 100.
  2. Usage: The computed property can be accessed just like any other property but derives its value from other backing fields.

These examples should give a beginner a comprehensive understanding of properties in C#.

Additional Topics:

  • Readonly Properties (Post-C# 6): Introduced in C# 6, allows defining a readonly property that can be set only within the constructor.

    using System;
    
    class Car
    {
        public string Make { get; }
        public string Model { get; }
    
        public Car(string make, string model)
        {
            Make = make;
            Model = model;
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            Car car = new Car("Toyota", "Corolla");
            Console.WriteLine($"Car Make: {car.Make}, Car Model: {car.Model}");
        }
    }
    
  • Expression-bodied Properties (Introduced in C# 6): Simplifies the syntax by allowing the body of a getter or setter to be an expression.

Top 10 Interview Questions & Answers on Properties in C#

1. What is the difference between fields and properties in C#?

Field: A field in C# is a variable or storage location that holds the actual data of an object. Fields are typically declared as private to prevent direct access from outside the class.

private int age;

Property: A property can be thought of as a way to access a private field while controlling read/write operations. It consists of a get accessor to retrieve the value and a set accessor to assign a new value.

public int Age
{
    get { return age; }
    set { age = value; }
}

You can also have an auto-implemented property in which C# compiler automatically creates a private field:

public int Age { get; set; }

2. How do I create a read-only property in C#?

To create a read-only property, you can omit the set accessor.

public string Name
{
    get;
    private set; // The setter is private, so it is accessible only within the class.
}

// Or with auto-implemented syntax using private setters:
public string Name { get; private set; } 

A private setter means that the Name property can only be set from within the same class.

3. Can a property have different access levels for its get and set methods?

Yes, you can have different access modifiers for the get and set methods of a property. This is commonly used to make a property read-only from outside the class but modifiable from inside.

public int SecretCode
{
    public get; // Accessible from outside the class
    private set; // Writeable only from within the class
}

4. How can I validate data when setting a property value in C#?

You can perform validation within the set accessor before assigning the value to the underlying field. For example, ensuring an age is not negative:

public int Age
{
    get { return age; }
    set
    {
        if (value < 0)
            throw new ArgumentOutOfRangeException(nameof(value), value, "Age cannot be negative.");
        age = value;
    }
}

// Auto-implemented version doesn't directly support validation, 
// but you can use backing fields as seen above.

5. What is a calculated property in C#?

A calculated property does not store its value in a field instead it returns a value computed dynamically at runtime:

public DateTime UtcNow => DateTime.UtcNow; // No backing field required

public double Average
{
    get
    {
        if (numbers.Count == 0) return 0;
        return numbers.Average();
    }
}

6. How can properties be used to implement lazy initialization?

Lazy initialization delays the creation of an object until it is needed. You can implement this pattern using properties combined with nullable types and the get accessor.

private List<double> expensiveNumbers;

public List<double> ExpensiveNumbers
{
    get
    {
        if (expensiveNumbers == null)
        {
            expensiveNumbers = ExpensiveMethodToGenerateNumbers();
        }
        return expensiveNumbers;
    }
}

private List<double> ExpensiveMethodToGenerateNumbers()
{
    return new List<double> { 1.1, 2.2, 3.3 }; // Represents some expensive calculation
}

The ExpensiveNumbers list will be instantiated only when it is accessed for the first time.

7. What are custom get and set accessors in C#?

Custom get and set accessors are simply user-defined implementations for accessing or assigning data to a property. They give you flexibility and control beyond the default auto-implemented properties.

public decimal Salary
{
    get
    {
        Console.WriteLine("Getting salary...");
        return salary;
    }
    set
    {
        Console.WriteLine("Setting salary...");
        salary = value;
    }
}

In this example, each time the Salary property is accessed, a message is printed.

8. Can a property be defined without a get or set method?

Yes, a property can be defined without one of them, making it write-only (set without get) or read-only (get without set). However, write-only properties are rarely used because they don't allow reading the state of the object.

Example of write-only property:

public bool CanUpdateInternally
{
    private get;
    set;
}

9. When should you use a backing field in a property?

Backing fields should be used when you need to perform some additional logic within the get and set accessors, such as validation, conversion, or lazy loading. Without a backing field, you cannot store the value persistently.

private string name;

public string Name
{
    get { return name; }
    set
    {
        if (string.IsNullOrEmpty(value))
            throw new ArgumentException("Name cannot be null or empty.", nameof(value));
        name = value;
    }
}

10. How are properties utilized in implementing data binding for UI applications?

Properties in C# play a crucial role in data binding scenarios. For instance, if you're building a WPF application, properties (often along with INotifyPropertyChanged interface implementation) bind the UI to backend data sources, enabling automatic updating of UI elements when the underlying data changes.

Here’s an example demonstrating how INotifyPropertyChanged works:

public class Employee : INotifyPropertyChanged
{
    private string name;

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public string Name
    {
        get { return name; }
        set
        {
            if (name != value)
            {
                name = value;
                OnPropertyChanged(nameof(Name));
            }
        }
    }
}

In this scenario, every time the Name property is updated, the OnPropertyChanged method is called, notifying bound UI elements about the change.


You May Like This Related .NET Topic

Login to post a comment.