DEV Community

mohamed Tayel
mohamed Tayel

Posted on

Mastering C# Fundamentals: Custom Types

Meta Description: Explore the five main custom types in .NET—classes, structs, enumerations, interfaces, and delegates. Learn how to effectively use and differentiate between value and reference types, with detailed examples and assignments to enhance your understanding.

With an understanding of value types and reference types, let’s explore custom types in .NET. We will focus on the five main types available in .NET, which include classes, enumerations, structs, interfaces, and delegates.

These types fall into two broad categories:

  1. Value Types: Stored on the stack and hold their values directly. These include Enumerations and Structs.
  2. Reference Types: Stored on the heap and hold a reference to the memory location. These include Classes, Interfaces, and Delegates.

Custom Types in Detail

1. Classes (Reference Type)

Classes are the most common custom type in .NET. They are reference types, which means instances of a class are stored on the heap.

Example:

class Employee
{
    public string Name { get; set; }
    public int Age { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

Classes support inheritance and polymorphism, making them ideal for complex business logic. When you create an instance of a class, you use the new keyword:

Employee emp = new Employee { Name = "Alice", Age = 30 };
Enter fullscreen mode Exit fullscreen mode

2. Enumerations (Value Type)

Enumerations represent a list of named constants. Enums are value types and help make code more readable.

Example:

enum Department
{
    HR,
    Finance,
    IT,
    Sales
}

// Usage:
Department dept = Department.IT;
Console.WriteLine(dept); // Output: IT
Enter fullscreen mode Exit fullscreen mode

Enums are especially useful for representing a predefined set of options, like status codes or user roles.

3. Structs (Value Type)

Structs are similar to classes but are value types. Structs are used for lightweight objects that do not require inheritance. Structs are created on the stack, making them more memory efficient in certain cases.

Example:

struct Point
{
    public int X { get; set; }
    public int Y { get; set; }

    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }
}

// Usage:
Point p1 = new Point(10, 20);
Console.WriteLine($"Point coordinates: X = {p1.X}, Y = {p1.Y}");
Enter fullscreen mode Exit fullscreen mode

Structs are useful for small data structures that contain a few variables.

4. Interfaces (Reference Type)

Interfaces define a contract that classes or structs must adhere to. They are reference types and contain method signatures without implementations. Interfaces are useful for defining common behavior that multiple classes can implement.

Example:

interface IEmployee
{
    void GetDetails();
    decimal CalculateSalary();
}

class Employee : IEmployee
{
    public string Name { get; set; }
    public int Age { get; set; }

    public void GetDetails()
    {
        Console.WriteLine($"Name: {Name}, Age: {Age}");
    }

    public decimal CalculateSalary()
    {
        return 1000.0M; // Example value
    }
}
Enter fullscreen mode Exit fullscreen mode

5. Delegates (Reference Type)

Delegates are reference types that hold references to methods. They are often used to implement callback methods and event-driven programming.

Example:

delegate void Notify(string message);

class Program
{
    static void Main()
    {
        Notify notify = ShowMessage;
        notify("Hello, Delegates!");
    }

    static void ShowMessage(string message)
    {
        Console.WriteLine(message);
    }
}
Enter fullscreen mode Exit fullscreen mode

Delegates provide flexibility, allowing methods to be assigned to variables and passed as arguments.

Namespaces and Using Statements

In .NET, types are organized in namespaces to prevent name collisions and keep the code organized. For instance, the System namespace contains basic classes such as Console, and System.Collections.Generic contains collection-related classes like List.

To use types from a namespace without fully qualifying them each time, we use the using directive:

using System.Collections.Generic;

List<int> numbers = new List<int> { 1, 2, 3 };
Enter fullscreen mode Exit fullscreen mode

Global Using Statements

From .NET 6 onwards, global using statements allow certain common namespaces to be used throughout the project without including them in every file. These global usings make code cleaner and reduce redundancy.

Exploring Types with Object Browser

Visual Studio’s Object Browser allows you to view the types and members available in your application, including those in your custom namespaces and third-party libraries.

  • To open Object Browser: Go to View > Object Browser in Visual Studio.
  • You can navigate through namespaces to discover built-in types and understand their methods and properties.

Adding Third-Party Libraries Using NuGet

.NET has a rich ecosystem of third-party libraries that can be added to projects using NuGet. For example, if we want to serialize an object to JSON, we can use Newtonsoft.Json:

  1. Install Newtonsoft.Json using NuGet.
  2. Add a using Newtonsoft.Json; statement.
  3. Use JsonConvert.SerializeObject() to convert an object to JSON.

Example:

using Newtonsoft.Json;

class Employee
{
    public string Name { get; set; }
    public int Age { get; set; }

    public string ConvertToJson()
    {
        return JsonConvert.SerializeObject(this);
    }
}

var emp = new Employee { Name = "Alice", Age = 30 };
Console.WriteLine(emp.ConvertToJson()); // Outputs JSON representation of Employee
Enter fullscreen mode Exit fullscreen mode

Assignments

Let’s practice with assignments at three levels of difficulty:

Level 1: Easy

  1. Create a Custom Enumeration Create an enum named JobTitle with values like Manager, Developer, Designer, and QA. Write a program that prints each title.
   enum JobTitle
   {
       Manager,
       Developer,
       Designer,
       QA
   }

   JobTitle title = JobTitle.Developer;
   Console.WriteLine($"Job Title: {title}");
Enter fullscreen mode Exit fullscreen mode
  1. Define and Use a Struct Create a Product struct with properties for Name and Price. Write a method to display the product's details.
   struct Product
   {
       public string Name { get; set; }
       public decimal Price { get; set; }

       public void Display()
       {
           Console.WriteLine($"Product: {Name}, Price: {Price}");
       }
   }

   Product product = new Product { Name = "Laptop", Price = 1200.99M };
   product.Display();
Enter fullscreen mode Exit fullscreen mode

Level 2: Medium

  1. Create an Interface and Implement It Create an interface called IVehicle with methods Start() and Stop(). Implement this interface in a Car class.
   interface IVehicle
   {
       void Start();
       void Stop();
   }

   class Car : IVehicle
   {
       public void Start()
       {
           Console.WriteLine("Car started.");
       }

       public void Stop()
       {
           Console.WriteLine("Car stopped.");
       }
   }

   Car myCar = new Car();
   myCar.Start();
   myCar.Stop();
Enter fullscreen mode Exit fullscreen mode
  1. Work with Delegates Create a delegate called MathOperation that takes two integers and returns an integer. Write methods for addition, subtraction, and multiplication, and assign them to the delegate.
   delegate int MathOperation(int x, int y);

   static int Add(int a, int b) => a + b;
   static int Subtract(int a, int b) => a - b;
   static int Multiply(int a, int b) => a * b;

   MathOperation operation = Add;
   Console.WriteLine($"Addition: {operation(5, 3)}");

   operation = Multiply;
   Console.WriteLine($"Multiplication: {operation(5, 3)}");
Enter fullscreen mode Exit fullscreen mode

Level 3: Difficult

  1. Create and Use a Class Library Create a class library named MathLibrary with a Calculator class that has methods for basic arithmetic operations. Create a console application that references MathLibrary and calls the Calculator methods.
   // In MathLibrary Project:
   public class Calculator
   {
       public int Add(int a, int b) => a + b;
       public int Subtract(int a, int b) => a - b;
       public int Multiply(int a, int b) => a * b;
   }

   // In Console Application:
   var calc = new MathLibrary.Calculator();
   Console.WriteLine(calc.Add(10, 5));
Enter fullscreen mode Exit fullscreen mode
  1. Use Newtonsoft.Json for Serialization Install Newtonsoft.Json via NuGet, create a Student class, and write a method to serialize it to JSON.
   using Newtonsoft.Json;

   class Student
   {
       public string FullName { get; set; }
       public int Grade { get; set; }

       public string Serialize()
       {
           return JsonConvert.SerializeObject(this);
       }
   }

   Student student = new Student { FullName

 = "John Doe", Grade = 12 };
   Console.WriteLine(student.Serialize());
Enter fullscreen mode Exit fullscreen mode
  1. Create and Use Custom Namespaces Create a custom namespace called Company.Finance with classes Accountant and Invoice. Use these classes in a different project by referencing it.

These examples and assignments will help you gain hands-on experience with different custom types, namespaces, and third-party libraries in .NET. Understanding these types will enhance your ability to write well-structured and maintainable code.

Top comments (0)