QUESTION 1:
Create a C# program that uses Dictionary to manage student records (name as key, marks as value)
with full CRUD operations (Add, Retrieve, Update, Delete) through a user-friendly console interface,
then compare its type safety and performance against Hashtable to demonstrate why generics are
preferred in modern .NET applications.
PROGRAM:
namespace Ass1
{
internal class Program
{
static void Main(string[] args)
{
//using name as key and marks as value
Dictionary<string, int> record = new Dictionary<string, int>();
int choice = 0;
do
{
[Link]("""
STUDENT RECORD
1)ADD
2)RETRIEVE
3)UPDATE
4)DELETE
5)EXIT
""");
choice = [Link]([Link]());
switch (choice)
{
case 1:
{
add(record);
break;
}
case 2:
{
retrieve(record);
break;
}
case 3:
{
update(record);
break;
}
case 4:
{
delete(record);
break;
}
default:
[Link]("WRONG CHOICE");
break;
}
while (choice != 5);
static void add( Dictionary<string,int> record)
{
[Link]("Enter name: ");
string name = [Link]();
if ([Link](name))
{
[Link]("This name already exists. Use UPDATE to
modify.");
return;
}
[Link]("Enter makrs: ");
int marks = [Link]([Link]());
[Link](name, marks);
}
static void retrieve(Dictionary<string, int> record)
{
if ([Link] == 0)
{
[Link]("The dictionary is empty.");
return;
}
[Link]("Enter name: ");
string name = [Link]();
if ([Link](name))
{
[Link]($"""
name:{name}
marks:{record[name]}
""");
}
else
[Link]("NOT FOUND!");
}
static void update(Dictionary<string, int> record)
{
if ([Link] == 0)
{
[Link]("The dictionary is empty.");
return;
}
[Link]("""
What do you want to update:
1)Name
2)Marks
3)Exit
""");
int choice = [Link]([Link]());
switch (choice)
{
case 1: // Update Name
[Link]("Enter the name you want to update: ");
string oldKey = [Link]();
if ()
{
[Link]("Name not found.");
break;
}
[Link]("Enter updated name: ");
string newKey = [Link]();
// Update key
int value = record[oldKey];
[Link](oldKey);
record[newKey] = value;
[Link]("Name updated successfully.");
break;
case 2: // Update Marks
[Link]("Enter the name whose marks you want to update:
");
string name = [Link]();
if ()
{
[Link]("Name not found.");
break;
}
[Link]("Enter updated marks: ");
if (, out int marks))
{
[Link]("Invalid input. Please enter a valid
number.");
break;
}
record[name] = marks;
[Link]("Marks updated successfully.");
break;
case 3:
return;
default:
[Link]("WRONG CHOICE");
break;
static void delete(Dictionary<string, int> record)
{
[Link]("Enter the name you want to remove: ");
string key = [Link]();
if ([Link](key))
{
[Link](key);
[Link]("Record removed successfully.");
}
else
{
[Link]("Name not found.");
}
}
}
}
COMPARISON WITH HASHTABLE
TYPE SAFETY
1. Type Safety in Dictionary<TKey, TValue>
• Dictionary<TKey, TValue> is a generic collection, meaning the key and value types are explicitly
defined when declaring the dictionary.
• This ensures that only the specified types can be used, reducing runtime errors.
Example:
Dictionary<string, int> studentMarks = new Dictionary<string, int>();
studentMarks["Alice"] = 90; // Valid
studentMarks["Bob"] = "A"; // Compilation error
Since studentMarks only accepts int values, assigning a string causes a compile-time error, making the
code safer.
2. Type Safety in Hashtable
• Hashtable stores both keys and values as object, meaning it allows different types to be stored
together.
• This requires explicit type casting when retrieving values, leading to potential runtime errors.
Example:
Hashtable studentMarks = new Hashtable();
studentMarks["Alice"] = 90;
studentMarks["Bob"] = "A"; // No compile-time error
int marks = (int)studentMarks["Bob"]; // Runtime error (InvalidCastException)
The cast to int will fail at runtime because "A" is a string, increasing the risk of errors.
PERFORMANCE
1. Performance of Dictionary<TKey, TValue>
• Dictionary<TKey, TValue> is optimized for speed using strongly-typed data and generic
collections.
• Lookups, insertions, and deletions have an average time complexity of O(1) due to
efficient hashing.
• Avoids boxing/unboxing, reducing memory overhead and improving execution speed.
Example:
Dictionary<string, int> studentMarks = new Dictionary<string, int>();
studentMarks["Alice"] = 90;
int marks = studentMarks["Alice"]; // No boxing/unboxing
2. Performance of Hashtable
• Hashtable uses object for storage, requiring boxing/unboxing when storing value types like int,
double, etc.
• This extra memory allocation and conversion slow down operations.
Boxing: The int value 90 is stored as an object, creating additional memory overhead.
Unboxing: When retrieving, the value must be cast back to int, causing performance loss.
Example:
Hashtable studentMarks = new Hashtable();
studentMarks["Alice"] = 90; // Boxing occurs
int marks = (int)studentMarks["Alice"]; // Unboxing occurs
QUESTION 2:
Demonstrate your understanding of boxing and unboxing by writing a C# program.
PROGRAM:
namespace Ass1
{
internal class Program
{
static void Main(string[] args)
{
int num = 42;
Print(num); // Boxing: int → object
object boxedValue = GetValue();
int originalValue = (int)boxedValue; // Unboxing: object → int
[Link]("Unboxed Value: " + originalValue);
}
static void Print(object obj) // Accepts any type
{
[Link]("Boxed Value: " + obj);
}
static object GetValue()
{
return 100; // Boxing: int → object
}
}
}