Compile vs Runtime Poly
Part of the Object Oriented Programming section of Coddy's C# journey — lesson 25 of 70.
Polymorphism means "many forms" - the ability for the same code to behave differently depending on context. C# supports two distinct types of polymorphism, and understanding when each is resolved helps you write more flexible code.
Compile-time polymorphism (also called static polymorphism) is resolved by the compiler before your program runs. Method overloading is the primary example - multiple methods share the same name but have different parameters:
public class Calculator
{
public int Add(int a, int b) => a + b;
public double Add(double a, double b) => a + b;
}
var calc = new Calculator();
calc.Add(5, 3); // Compiler picks int version
calc.Add(5.0, 3.0); // Compiler picks double versionThe compiler examines the argument types and selects the correct method at compile time. This decision is fixed before the program ever executes.
Runtime polymorphism (dynamic polymorphism) is resolved while the program runs. This happens with virtual and override methods - the actual type of the object determines which method executes:
Animal pet = new Dog(); // Declared as Animal, actually a Dog
pet.Speak(); // Calls Dog's Speak() at runtimeThe compiler doesn't know which Speak() will run - that decision happens at runtime based on the object's true type. This is what makes inheritance-based polymorphism so powerful for building flexible, extensible systems.
Challenge
EasyLet's build a converter system that demonstrates both types of polymorphism in action. You'll create a class that uses method overloading (compile-time polymorphism) alongside an inheritance hierarchy that uses virtual/override methods (runtime polymorphism).
You'll organize your code across four files:
Converter.cs: Define aConverterclass in theConversionnamespace. This class demonstrates compile-time polymorphism through method overloading. Create three overloadedConvertmethods:Convert(int value)returns"Integer: {value}"Convert(double value)returns"Double: {value}"Convert(string value)returns"String: {value}"
Shape.cs: Define a baseShapeclass in theConversionnamespace. This class has aNameproperty (string) and a constructor that sets it. Include avirtualmethod calledDescribe()that returns"This is a {Name}".Circle.cs: Define aCircleclass in theConversionnamespace that inherits fromShape. Add aRadiusproperty (double). The constructor accepts a radius and passes"Circle"to the base constructor. OverrideDescribe()to return"This is a Circle with radius {Radius}".Program.cs: In your main file, demonstrate both types of polymorphism. First, create aConverterand call all three overloaded methods with input values. Then create aCircle, store it in aShapevariable, and callDescribe()to show runtime polymorphism.
You will receive four inputs:
- An integer value
- A double value
- A string value
- A circle radius (double)
Print the output in this format:
Compile-time Polymorphism:
{Convert(int) result}
{Convert(double) result}
{Convert(string) result}
Runtime Polymorphism:
{Describe() result from Shape variable holding Circle}For example, if the inputs are 42, 3.14, Hello, and 5.5, the output should be:
Compile-time Polymorphism:
Integer: 42
Double: 3.14
String: Hello
Runtime Polymorphism:
This is a Circle with radius 5.5Notice the key difference: the compiler decides which Convert method to call based on argument types at compile time, while the Describe() method is resolved at runtime based on the actual object type, even though it's stored in a Shape variable!
Cheat sheet
Polymorphism means "many forms" - the ability for the same code to behave differently depending on context.
Compile-time polymorphism (static polymorphism) is resolved by the compiler before the program runs. Method overloading is the primary example:
public class Calculator
{
public int Add(int a, int b) => a + b;
public double Add(double a, double b) => a + b;
}
var calc = new Calculator();
calc.Add(5, 3); // Compiler picks int version
calc.Add(5.0, 3.0); // Compiler picks double versionThe compiler examines argument types and selects the correct method at compile time.
Runtime polymorphism (dynamic polymorphism) is resolved while the program runs using virtual and override methods:
Animal pet = new Dog(); // Declared as Animal, actually a Dog
pet.Speak(); // Calls Dog's Speak() at runtimeThe actual type of the object determines which method executes at runtime, not the declared variable type.
Try it yourself
using System;
using Conversion;
class Program
{
public static void Main(string[] args)
{
// Read inputs
int intValue = Convert.ToInt32(Console.ReadLine());
double doubleValue = Convert.ToDouble(Console.ReadLine());
string stringValue = Console.ReadLine();
double radius = Convert.ToDouble(Console.ReadLine());
// TODO: Demonstrate Compile-time Polymorphism
// Create a Converter object and call all three overloaded Convert methods
Console.WriteLine("Compile-time Polymorphism:");
// Call Convert with intValue, doubleValue, and stringValue
// TODO: Demonstrate Runtime Polymorphism
// Create a Circle object and store it in a Shape variable
// Then call Describe() on the Shape variable
Console.WriteLine("Runtime Polymorphism:");
// Create Circle and call Describe()
}
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesNamespaces & DirectivesIntro to Classes & ObjectsThe 'this' KeywordMethods and ParametersFields vs PropertiesConstructorsObject InitializersRecap - Simple Calculator4Inheritance
Basic Inheritance (:) SyntaxThe 'base' KeywordVirtual & Override KeywordsSealed ClassesThe 'object' Base ClassRecap - Employee Hierarchy7Advanced Features
Operator OverloadingIndexers (this[])ToString() OverrideExtension MethodsRecap - Custom List2Properties & Static Members
Auto-Implemented PropertiesRead/Write-Only PropertiesStatic Fields & MethodsStatic ClassesExpression-Bodied Members5Polymorphism & Interfaces
Compile vs Runtime PolyInterface vs Abstract ClassMultiple InterfacesExplicit InterfacesUpcasting & DowncastingRecap - Shape Calculator