Oops in C#
Oops in C#
NET Framework
Here, I am going to give you an overview of the DOT NET Framework. This is important for
you as a dot net developer to know the history and evolution of the DOT NET Framework.
Here, in this session, first, we will discuss what was there before the .NET Framework and
what problems we face in that, and how we overcome all those problems in the .NET
Framework. Before DOT NET Framework COM is there. So, let us first discuss what is COM
and what problems we face in COM.
What is COM?
COM stands for Component Object Model. The COM is one of the Microsoft Frameworks.
Using this Framework, we can develop Windows Applications (Desktop or Standalone
Applications for Windows OS) as well as Web Applications. In earlier COM, VB is the
programming language that is used to implement Windows applications and ASP is the
technology used to implement web applications.
What are the disadvantages of COM?
There are two major disadvantages of the COM Framework. They are as follows:
1. Incomplete Object-Oriented Programming means it will not support all the features
of OOPs.
2. Platform Dependent means COM applications can run on only Windows OS.
// Methods
public void Display()
{
Console.WriteLine($"Id: {Id}, Name: {Name}");
}
}
Object Creation:
C#
MyClass obj1 = new MyClass();
obj1.Id = 1;
obj1.Name = "John Doe";
obj1.Display();
// Part 2
public partial class MyClass
{
// ...
}
Static Class:
o Contains only static members (methods and fields).
o Cannot be instantiated.
o Used for utility methods and constants.
o Example:
C#
public static class MathUtils
{
public static double PI = 3.14159;
public static int Add(int a, int b)
{
return a + b;
}
}
7. Key Points
Classes and objects are fundamental concepts in object-oriented programming.
Understanding the relationship between classes and objects is essential for effective C#
programming.
Different types of classes offer varying levels of flexibility and control.
Constructors in C#
1. Introduction
A constructor is a special method within a class that is automatically called when an object of
that class is created.
Its primary purpose is to initialize the object's state (properties/fields).
2. Key Characteristics
Name: The constructor's name must be the same as the class name.
Return Type: Constructors do not have a return type, not even void.
Purpose:
o Initialize the object's properties.
o Allocate necessary resources.
Types:
o Default Constructor (Parameterless):
A constructor that takes no arguments.
The compiler provides a default constructor if no other constructors are
defined in the class.
o Parameterized Constructor:
A constructor that accepts arguments.
Allows for flexible object initialization with different values.
3. Implicit Constructor
The compiler automatically generates a default constructor (parameterless) if no other
constructors are defined explicitly in the class.
This implicit constructor initializes the fields of the class with their default values (e.g., 0 for
integers, null for strings).
4. Explicit Constructor
A constructor that is defined explicitly by the programmer.
Can be parameterless or parameterized.
Allows for custom initialization logic.
5. Example: Implicit Constructor
C#
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
}
public Employee()
{
Console.WriteLine("Default Constructor Called");
}
}
7. Example: Explicit Parameterized Constructor
C#
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
Constructors in C#
1. Introduction
A constructor is a special method within a class that is automatically called whenever
an object of that class is created.
Its primary purpose is to initialize the object's state (properties/fields) with appropriate
values.
2. Key Characteristics
Name: The constructor's name must be the same as the class name.
Return Type: Constructors do not have a return type, not even void.
Purpose:
o Initialize the object's properties.
o Allocate necessary resources.
o Perform custom logic at object creation.
Types:
o Default Constructor (Parameterless):
A constructor that takes no arguments.
The compiler provides a default constructor if no other constructors are
defined in the class. It initializes fields with their default values (e.g., 0
for integers, null for strings).
o Parameterized Constructor:
A constructor that accepts arguments.
Allows for flexible object initialization with different values.
3. Implicit Constructor
The compiler automatically generates a default constructor (parameterless) if no other
constructors are defined explicitly in the class.
4. Explicit Constructor
A constructor that is defined explicitly by the programmer.
Can be parameterless or parameterized.
Allows for custom initialization logic.
5. Example: Implicit Constructor
C#
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
}
public Employee()
{
Console.WriteLine("Default Constructor Called");
}
}
7. Example: Explicit Parameterized Constructor
C#
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
Console.ReadLine();
}
}
Export to Sheets
3. Examples
Static Constructor:
C#
public class MyClass
{
public static int StaticCount;
static MyClass()
{
Console.WriteLine("Static Constructor Called");
StaticCount = 0;
}
public MyClass()
{
Console.WriteLine("Non-Static Constructor Called");
InstanceCount = 1;
}
// Creating an object will trigger the static constructor (if not already triggered)
// and then the instance constructor
MyClass obj1 = new MyClass();
static MyClass()
{
Console.WriteLine("Static Constructor Called");
StaticCount = 0;
}
public MyClass()
{
Console.WriteLine("Non-Static Constructor Called");
InstanceCount = 1;
}
}
7. Diagram
Openindownaveen-metta.medium.com
class diagram illustrating the execution order of static and nonstatic constructors
8. Conclusion
Static and non-static constructors play crucial roles in object initialization in C#.
Understanding their differences and how they are executed is essential for writing
efficient and well-structured C# code.
By effectively using static and non-static constructors, you can manage the
initialization of class members and control the execution flow within your classes.
Private Constructors in C#
1. Introduction
A private constructor is a constructor declared with the private access modifier.
It restricts object creation from outside the class.
2. Key Characteristics
Access: Can only be accessed within the class itself.
Object Creation:
o Cannot be used to create objects directly from outside the class.
o Can be used to create objects within the same class.
Inheritance:
o If a class has only a private constructor, it cannot be inherited by other classes
(except nested classes within the same class).
3. Examples
Private Constructor Only:
C#
public class MyClass
{
private MyClass()
{
Console.WriteLine("Private Constructor Called");
}
private Singleton()
{
// ...
}
Destructors in C#
1. Introduction
A destructor is a special method in C# that is automatically called by the garbage
collector when an object is no longer in use.
Its primary purpose is to perform any necessary cleanup operations before the object's
memory is reclaimed.
2. Key Characteristics
Name: The destructor's name is the same as the class name preceded by a tilde (~).
Access Modifier: Destructors cannot have any access modifiers (public, private,
protected).
Parameters: Destructors cannot have any parameters.
Return Type: Destructors do not have a return type.
Execution:
o Called implicitly by the garbage collector when the object is eligible for
garbage collection.
o The exact timing of destructor execution is not deterministic.
3. When is an Object Eligible for Garbage Collection?
When all references to the object have been lost.
When the application terminates.
4. Example
C#
public class MyClass
{
public MyClass()
{
Console.WriteLine("Constructor Called");
}
~MyClass()
{
Console.WriteLine("Destructor Called");
}
}
5. Calling the Garbage Collector
You can request the garbage collector to run by calling GC.Collect().
However, relying heavily on GC.Collect() can negatively impact performance.
6. Destructor Implementation
Destructors are implemented using the Finalize method in the .NET runtime.
The Finalize method is called recursively for all objects in the inheritance chain.
7. Important Points
Destructors cannot be called explicitly.
Destructors should be used sparingly and only when necessary to release unmanaged
resources (e.g., file handles, database connections).
Relying heavily on destructors can negatively impact performance.
8. Dispose Pattern
The preferred way to release unmanaged resources is by implementing the
IDisposable interface and providing a Dispose() method.
The Dispose() method allows for explicit resource cleanup and provides more control
over the timing of resource release.
The Dispose() method should be called by the user of the object when they are
finished with it.
9. Code Example (Dispose Pattern)
C#
public class MyClass : IDisposable
{
private bool disposedValue = false; // To detect redundant calls
~MyClass()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(false);
}
~MyClass()
{
Dispose(false);
}
}
By following these practices, you can ensure efficient memory management and
prevent memory leaks in your .NET applications.
Additional Notes
The GC is a complex system with various configurations and settings you can explore
for advanced memory management scenarios.
Tools like the .NET Memory Profiler can help you analyze memory usage and
identify potential issues.
~ResourceHolder()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(false);
}
Abstraction in C#
Abstraction is a fundamental concept in object-oriented programming (OOP) that focuses on
exposing essential functionalities (what an object does) while hiding implementation details (how it
does it). It simplifies complex systems by breaking them down into smaller, more manageable units.
This promotes code reusability, maintainability, and flexibility.
Key Concepts
Focus on Behavior: Define the services (methods) an object provides without revealing the
underlying logic. Users interact with these services without needing to know the intricate
workings of the object.
Data Hiding: Encapsulate data (member variables) within a class and control access through
methods (getters and setters) or properties. This safeguards data integrity and prevents
unauthorized modifications.
Interfaces: Define contracts outlining the services an object must implement. Classes can
inherit from interfaces and provide concrete implementations for the specified methods.
This promotes loose coupling and allows for interchangeable implementations.
Abstract Classes: Serve as blueprints for derived classes by defining a set of abstract
methods (without implementation) and potentially concrete methods. Derived classes
inherit and provide implementations for abstract methods, achieving partial or complete
abstraction.
Benefits of Abstraction
Simplified Code: Users focus on how to utilize an object's services without getting bogged
down in implementation details.
Increased Maintainability: Changes to internal workings don't necessarily affect how users
interact with the object, making modifications easier and less error-prone.
Enhanced Reusability: Well-abstracted components can be reused in different contexts
without modification, promoting code efficiency.
Improved Security: Sensitive data can be protected by restricting access through methods
and properties, preventing unauthorized modifications.
Flexibility in Design: Abstract classes and interfaces facilitate the creation of interchangeable
implementations, fostering a more flexible and adaptable codebase.
Implementation Examples
1. Abstraction Using Interfaces
C#
public interface IShape
{
double CalculateArea();
}
// Usage
IShape circle = new Circle { Radius = 5 };
IShape square = new Square { SideLength = 3 };
// Usage
Shape circle = new Circle { Radius = 5 };
Shape square = new Square { SideLength = 3 };
class Program
{
static void Main(string[] args)
{
Dog myDog = new Dog();
myDog.MakeSound(); // Inherited from Animal
myDog.Bark(); // Defined in Dog
}
}
Benefits of Inheritance
Code Reusability: Avoids code duplication by inheriting common properties and behaviors
from a parent class.
Improved Code Organization: Creates a hierarchical structure that reflects real-world
relationships.
Enhanced Maintainability: Changes made to the parent class are automatically reflected in
all derived classes.
Extensibility: Allows for the creation of specialized classes by adding new features or
modifying existing behavior.
Key Points
Inheritance is a powerful tool for creating flexible and reusable code.
Understanding the rules of inheritance is crucial for effective object-oriented design.
Utilize inheritance judiciously to maintain a well-structured and maintainable codebase.
Types of Inheritance in C#
In C#, inheritance can be broadly classified into two main types:
1. Implementation Inheritance
Definition: This type of inheritance occurs when a class derives from another class.
Characteristics:
o The derived class inherits both data members (fields) and member functions
(methods) from the base class.
o It allows for code reuse and promotes a hierarchical relationship between classes.
o Subtypes:
Single Inheritance: A class inherits from only one immediate base class.
(e.g., class DerivedClass : BaseClass { ... })
Multi-level Inheritance: A chain of inheritance where a class inherits from
another derived class. (e.g., class A { ... }, class B : A { ... }, class C : B { ... })
Hierarchical Inheritance: Multiple classes inherit from a single base class.
(e.g., class A { ... }, class B : A { ... }, class C : A { ... })
2. Interface Inheritance
Definition: This type of inheritance occurs when a class implements an interface.
Characteristics:
o A class that implements an interface must provide concrete implementations for all
the methods declared in the interface.
o Interfaces define a contract that classes must adhere to.
o Allows for polymorphism and loose coupling between classes.
Key Points:
Multiple Inheritance (with Classes): C# does not directly support multiple inheritance with
classes. This means a class cannot inherit from multiple base classes directly.
Hybrid Inheritance: A combination of various inheritance types (single, multi-level,
hierarchical) can be considered hybrid inheritance. However, it's not a distinct category in C#.
Example: Implementation Inheritance
C#
public class Animal
{
public void MakeSound()
{
Console.WriteLine("Generic animal sound");
}
}
class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
}
Here, Employee HAS-A Address through the member variable Address.
Key Differences
Feature IS-A (Inheritance) HAS-A (Composition)
Nature Inheritance (parent-child) Compositional
Coupling Stronger Looser
Usage Extension, specialization Requires functionality/properties
Flexibility Limited (tightly bound) More flexible (easily modified)
Export to Sheets
Choosing the Right Relationship
The choice between IS-A and HAS-A depends on the nature of the relationship between your classes.
Ask yourself:
Is the derived class a specialized version of the base class? (IS-A)
Does the container class need functionalities provided by another class's object? (HAS-A)
Here's a quick guideline:
If the statement "DerivedClass IS-A BaseClass" makes sense, use inheritance.
If the statement "ContainerClass HAS-A AnotherClass" makes sense, use composition.
Remember
Inheritance is implemented using the : syntax (e.g., class DerivedClass : BaseClass { ... }).
Composition is simply declaring a variable of another class inside a class.
Generalization and Specialization in C#
Generalization
Concept:
o Identifying commonalities among a group of existing classes and creating a new,
more general (parent) class.
o This parent class encapsulates the shared features of the child classes.
Example:
o Consider classes like Circle, Square, and Rectangle. They all share the concept of
being "shapes."
o We can create a generalized class called Shape that includes common properties like
Area and Perimeter.
o Circle, Square, and Rectangle would then inherit from the Shape class, inheriting the
common properties and implementing their specific area and perimeter calculations.
Specialization
Concept:
o Creating new, more specialized classes (child classes) from an existing base class.
o These derived classes inherit the properties and behaviors of the base class and add
their own unique characteristics.
Example:
o You have a base class Animal with general characteristics like Eat() and Sleep().
o You can create specialized classes like Dog, Cat, and Bird that inherit from Animal
and add specific behaviors like Bark(), Meow(), and Fly().
Key Differences
Feature Generalization Specialization
Direction Bottom-up (from specific to general) Top-down (from general to specific)
Purpose Identify commonalities, create a superclass Create specialized versions of a base class
Base Class Created after child classes exist Already exists
Export to Sheets
In C#
Generalization: Often achieved using interfaces or abstract classes.
Specialization: Achieved through class inheritance.
Example (Generalization)
C#
interface IShape
{
double CalculateArea();
}
Console.WriteLine("\nCurrent Account:");
IBankAccount currentAccount = new CurrentAccount();
currentAccount.DepositAmount(500);
currentAccount.DepositAmount(1500);
currentAccount.WithdrawAmount(2600);
currentAccount.WithdrawAmount(1000);
Console.WriteLine($"Current Account Balance: {currentAccount.CheckBalance()}");
Console.ReadLine();
}
}
Key Benefits
Polymorphism: The IBankAccount interface allows you to treat both SavingAccount and
CurrentAccount objects uniformly.
Extensibility: You can easily add new account types (e.g., "Fixed Deposit") by creating new
classes that implement the IBankAccount interface.
Maintainability: Changes to the interface will automatically affect all implementing classes,
ensuring consistency across the system.
Multiple Inheritance in C#
C# does not directly support multiple inheritance for classes. This means a class can only inherit
from one parent class at a time. However, interfaces provide a way to achieve similar functionality.
Why not Multiple Inheritance with Classes?
The primary reason for not allowing multiple inheritance with classes is the ambiguity problem.
Imagine a scenario where two parent classes have methods with the same name and signature.
When inheriting from both classes, the compiler wouldn't know which method implementation to
use, leading to errors.
Interfaces to the Rescue
Interfaces define contracts that classes can implement. A class can implement multiple interfaces,
inheriting their methods and properties without the ambiguity problem. Here's how it works:
Interfaces only contain method declarations, not implementations.
Classes implementing an interface must provide implementations for all declared methods.
Benefits of Using Interfaces for Multiple Inheritance
Flexibility: Classes can inherit behavior from multiple interfaces without conflicts.
Extensibility: New interfaces can be created without modifying existing classes.
Loose Coupling: Interfaces promote loose coupling between classes, making code more
maintainable and testable.
Example: Bank Account System
Let's consider a bank account system with different account types (Savings and Current). Here's how
we can use interfaces for multiple inheritance:
1. Define an IBankAccount interface with common functionalities like Deposit, Withdraw, and
CheckBalance.
2. Create separate SavingsAccount and CurrentAccount classes implementing IBankAccount.
3. Each class provides specific implementations for deposit/withdrawal rules based on their
account type.
Code Example
C#
interface IBankAccount
{
bool Deposit(decimal amount);
bool Withdraw(decimal amount);
decimal CheckBalance();
}
1. github.com
github.com
Types of Polymorphism in C#
There are two main types of polymorphism in C#:
1. Compile-Time Polymorphism (Static Polymorphism, Early Binding):
o The behavior of a method is determined at compile time based on the method
signature (name and number and types of parameters).
o Achieved through method overloading.
o Method overloading allows multiple methods with the same name but different
signatures within the same class.
o The compiler selects the appropriate method based on the arguments used in the
call.
2. Run-Time Polymorphism (Dynamic Polymorphism, Late Binding):
o The behavior of a method is determined at runtime based on the object's actual
type.
o Achieved through inheritance and method overriding.
o A subclass (derived class) can override a method inherited from its parent (base
class) to provide its own implementation.
o When a method is called on a reference variable of the parent class type, the actual
object's type determines which method implementation is executed at runtime.
Benefits of Polymorphism
Flexibility: Code can adapt to different situations based on the object type.
Reusability: Methods can be written in a generic way to handle different types of objects.
Maintainability: Code is easier to understand and modify because the logic is centralized in
methods.
Example: Shape Inheritance
C#
class Shape
{
public virtual void Draw() // Virtual method for overriding
{
Console.WriteLine("Drawing a shape");
}
}
class Circle : Shape
{
public override void Draw()
{
Console.WriteLine("Drawing a circle");
}
}
class Program
{
static void Main(string[] args)
{
Shape[] shapes = { new Circle(), new Square() };
foreach (Shape shape in shapes)
{
shape.Draw(); // Calls the appropriate Draw method based on object type at runtime
}
}
}
Output:
Drawing a circle
Drawing a square
Key Points
Polymorphism is a powerful tool for writing flexible and reusable code.
Compile-time polymorphism uses method signatures for binding, while run-time
polymorphism uses object types for binding.
Inheritance and method overriding are essential for achieving run-time polymorphism.
Consider using interfaces for alternative inheritance-like behavior without the ambiguity
problem of multiple class inheritance.
Method Overloading in C#
Method overloading is a fundamental concept in object-oriented programming (OOP) that allows you
to define multiple methods with the same name within a class, but with different signatures. The
signature of a method is determined by the number, type, and order of its parameters.
Key Points:
Allows for cleaner and more intuitive code.
Improves code readability and maintainability.
Enables polymorphism (one method name, different behaviors based on arguments).
Achieved through differences in method signatures, not return types.
Benefits of Method Overloading:
Flexibility: Code can adapt to different situations based on the arguments provided.
Reusability: Methods can be written in a generic way to handle various data types.
Readability: Code becomes more readable as overloaded methods often have clear names
reflecting their purpose.
Example:
C#
class Shape
{
public virtual void Draw() // Virtual method for overriding
{
Console.WriteLine("Drawing a shape");
}
}
class Program
{
static void Main(string[] args)
{
Shape[] shapes = { new Circle(), new Square() };
foreach (Shape shape in shapes)
{
shape.Draw(); // Calls the appropriate Draw method based on object type at runtime
(polymorphism)
}
}
}
Output:
Drawing a circle
Drawing a square
When to Use Method Overloading:
When you need to perform the same operation on different data types.
When you want to provide multiple ways to call a method with varying amounts of data.
To improve code readability by using descriptive method names with overloaded versions for
different scenarios.
Things Not Considered in Method Signature:
Return Type: While methods can have different return types, it's not part of the signature for
overloading. You cannot overload methods based solely on return type differences.
Access Specifiers (public, private, protected): These can be different for overloaded
methods.
Access Modifiers (sealed, static, virtual): These can also be different for overloaded
methods.
Overloading vs. Overriding:
Overloading: Occurs within the same class, methods have the same name but different
signatures.
Overriding: Occurs in inheritance hierarchies, a subclass redefines a method inherited from
its parent class.
Additional Notes:
Method overloading is resolved at compile time.
C# allows overloading constructors (special methods for object creation) based on parameter
differences.
Method Overriding in C#
Method overriding is a fundamental object-oriented programming (OOP) concept that allows you to
redefine the behavior of an inherited method in a subclass. It enables polymorphism, a cornerstone
of OOP that allows for "one method name, different behaviors based on arguments."
Key Points:
Redefining Inherited Methods: Subclasses (derived classes) can override methods inherited
from their parent classes (base classes).
Signature Matching: The overriding method must have the same signature (name,
parameter list) as the overridden method.
Access Modifiers: Overridden methods can have different access modifiers (public, private,
protected) than the overridden method.
Virtual Keyword: The parent class method must be declared as virtual to allow overriding in
subclasses.
override Keyword: The subclass method uses the override keyword to explicitly indicate it's
overriding a parent class method.
Benefits:
o Flexibility: Code adapts to specific situations based on arguments provided.
o Reusability: Methods are written generically to handle various data types.
o Readability: Clear method names and overriding behavior enhance code clarity.
Diagram:
+--------------+
| Base Class | (Parent)
+--------------+
|
(Inherits) +--------------+
| | Sub Class 1 | (Child 1)
+--------------+ |
| +--------------+
| (Inherits) | Sub Class 2 | (Child 2)
+--------------+ |
+--------------+
| Sub Class N | (Child N)
+--------------+
class Program
{
static void Main(string[] args)
{
Shape[] shapes = { new Circle(), new Square() };
foreach (Shape shape in shapes)
{
shape.Draw(); // Calls the appropriate Draw method based on object type at runtime
(polymorphism)
}
}
}
Output:
Drawing a circle
Drawing a square
Explanation:
1. The Shape class defines a Draw() method declared as virtual. This allows subclasses to
override it.
2. The Circle and Square classes inherit from Shape.
3. Both Circle and Square override the Draw() method with their specific implementation for
drawing a circle and a square, respectively.
4. In the Main() method, an array of Shape objects holds instances of Circle and Square.
5. The foreach loop iterates through the shapes array.
6. When shape.Draw() is called, the runtime determines the actual type of the object (Circle or
Square) and invokes the overridden method defined in that specific subclass. This
demonstrates polymorphism in action.
Key Differences from Method Overloading:
Feature Method Overriding Method Overloading
Signature Same name, same signature Same name, different signature
Location Subclass Same class
Inheritance Required Not required
Keyword override keyword used No special keyword needed
Purpose Redefine inherited behavior Provide multiple functionalities
Polymorphism Enables dynamic polymorphism Enables static polymorphism
Export to Sheets
Additional Notes:
Method overriding is resolved at runtime.
C# allows overriding constructors (special methods for object creation) based on parameter
differences.
Overridden methods can call the overridden method using the base keyword.
Method Hiding in C#
Method Hiding (also known as Shadowing) allows you to redefine a method inherited from a base
class in a derived class, using the same name and signature (name and parameter list). However,
unlike Method Overriding, it's done without explicitly declaring the derived class method as override.
Key Points:
Redefining Inherited Methods: Derived classes can hide inherited methods from the base
class.
Signature Matching: The hidden method must have the same signature as the base class
method.
Access Modifiers: Visibility of the hidden method can be different from the base class
method.
No virtual or override Keywords: Unlike Overriding, neither virtual nor override keywords
are used.
Optional new Keyword: While not strictly necessary, using new explicitly clarifies to the
compiler that you intend to hide the base class method.
Compiler Warning: Without the new keyword, the compiler will issue a warning about hiding
the base class method.
Diagram:
+--------------+
| Base Class | (Parent)
+--------------+
|
(Inherits) +--------------+
| | Derived Class | (Child)
+--------------+
|
| (Hides Methods)
Code Example:
C#
class Shape
{
public void Draw() // Base class method
{
Console.WriteLine("Drawing a shape");
}
}
class Program
{
static void Main(string[] args)
{
Shape[] shapes = { new Circle(), new Square() };
foreach (Shape shape in shapes)
{
shape.Draw(); // Calls the appropriate Draw method based on object type
}
}
}
Output:
Drawing a circle
Drawing a square
Explanation:
1. The Shape class defines a Draw() method.
2. The Circle class inherits from Shape.
3. The Circle class defines its own Draw() method with the new keyword, hiding the base class
method.
4. The Square class inherits from Shape and overrides the Draw() method using the override
keyword (optional for non-abstract methods).
5. In the Main() method, an array of Shape objects holds instances of Circle and Square.
6. The foreach loop iterates through the shapes array.
7. When shape.Draw() is called, the runtime determines the actual type of the object (Circle or
Square) and invokes the appropriate hidden or overridden method defined in that specific
subclass.
Key Differences from Method Overriding:
Feature Method Hiding Method Overriding
Signature Same name, same signature Same name, same signature
Location Derived class (without override) Derived class (with override)
Required (base class method must
Inheritance Not required
be virtual)
No special keyword needed (optional
Keyword override keyword used
new)
Purpose Hide base class behavior Redefine base class behavior
Compiler Warning Warning if no new keyword No warning
Accessing Base Class Not directly accessible using derived Can be accessed using base
Method class instance keyword
Export to Sheets
When to Use Method Hiding:
You don't want the derived class to inherit the base class method behavior but want to keep
the same method name and signature.
You're working with legacy code where overriding wasn't used consistently.
You need to explicitly indicate that a method is intended to hide the base class method
(using new).
Considerations:
Method hiding can make code less readable and maintainable as the base class method is no
longer directly accessible through the derived class instance.
Overriding is generally preferred as it maintains a clear relationship between base and
derived class methods.
Partial Classes and Partial Methods in C#
Partial Classes
Concept: Allow you to split the definition of a class across multiple files.
Syntax: Use the partial keyword before the class declaration in each file.
Benefits:
o Improved Code Organization: Large classes can be divided into smaller, more
manageable units.
o Collaboration: Multiple developers can work on different parts of a class
simultaneously.
o Code Generation: Useful for code generated by tools like Entity Framework, where
you can add custom logic to auto-generated classes.
Example:
File 1: Employee.cs
C#
public partial class Employee
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
File 2: Employee.cs
C#
public partial class Employee
{
public double Salary { get; set; }
public void CalculateSalary()
{
// Calculate salary logic
}
}
Partial Methods
Concept: Allow you to define a method signature without an implementation. The
implementation can be provided in another part of the partial class.
Syntax:
o Declare the method with the partial keyword and void return type.
o Provide the implementation of the partial method in another part of the partial
class.
Behavior:
o If the implementation is not provided, the compiler removes the partial method and
all calls to it.
o Useful for optional behavior or code generation scenarios.
Example:
File 1: MyClass.cs
C#
public partial class MyClass
{
public void DoSomething()
{
Console.WriteLine("Doing something...");
LogEvent(); // Call to the partial method
}