Skip to Content
Course content

175: The is and as Operators

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've seen this happen in almost every junior developer's first big project. You're building a system with a base class—let's say a game inventory—and you start adding specialized items. Everything works great until you try to treat a generic item as a specific one without checking first. Then, the whole application crashes with an InvalidCastException.

public class Item { public string Name { get; set; } }
public class Weapon : Item { public int Damage { get; set; } }
public class Potion : Item { public int HealAmount { get; set; } }

public class InventoryManager
{
    public void PrintItemDetails(Item item)
    {
        // This is the "danger zone"
        Weapon weapon = (Weapon)item; 
        Console.WriteLine($"Weapon Damage: {weapon.Damage}");
    }
}

// This works fine:
manager.PrintItemDetails(new Weapon { Name = "Iron Sword", Damage = 10 });

// This crashes the program:
manager.PrintItemDetails(new Potion { Name = "Health Potion", HealAmount = 20 });

The Danger of the Hard Cast

The problem here is the "hard cast"—that (Weapon)item line. You're essentially telling the C# compiler, "I know for a fact this is a Weapon; just force it." When you pass in a Potion, the runtime realizes a potion isn't a weapon and throws an exception. In a real production environment, this is how you get 2:00 AM bug reports.

Safe Checking with Type Pattern Matching

The modern way to handle this is using the is operator. In older versions of C#, is just returned a boolean. But now, we have "pattern matching," which lets you check the type and create a new variable all in one go. It's significantly cleaner.

public void PrintItemDetails(Item item)
{
    if (item is Weapon weapon)
    {
        // 'weapon' is only available inside this block
        Console.WriteLine($"Weapon Damage: {weapon.Damage}");
    }
    else if (item is Potion potion)
    {
        Console.WriteLine($"Potion Healing: {potion.HealAmount}");
    }
    else
    {
        Console.WriteLine($"Generic Item: {item.Name}");
    }
}

I personally prefer this approach because it's explicit. You're asking a question ("Is this a weapon?") and if the answer is yes, C# gives you a typed variable to work with immediately. No double-casting required.

The 'Try and See' Approach with the as Operator

Then there's the as operator. While is is like asking a question, as is more like an attempt. It tries to cast the object to the specified type. If it succeeds, you get the object; if it fails, it doesn't throw an exception—it simply returns null.

public void ApplyWeaponBonus(Item item)
{
    Weapon weapon = item as Weapon;

    if (weapon != null)
    {
        Console.WriteLine($"Applying bonus to {weapon.Name}!");
    }
}

You might wonder why you'd use as when is pattern matching exists. The as operator is still incredibly useful when you're dealing with a sequence of operations where a null result is a natural part of the logic, or when you want to perform the cast once and use the resulting variable across a larger block of code without being nested inside an if statement.

Just remember: never use as with value types (like int or bool) because they can't be null. Stick to reference types or nullable types.




📋 Practical Task

Implement a Smart NPC Dialogue Handler

You are building a dialogue system where different types of NPCs provide different kinds of information. You have a base NPC class and two subclasses: QuestGiver (which has a QuestName property) and Merchant (which has a StoreInventoryCount property).

Your task is to complete the DialogueManager class. Write a method called InteractWithNPC(NPC npc) that uses the is operator with pattern matching to:

  • If the NPC is a QuestGiver, print: "Quest available: [QuestName]"
  • If the NPC is a Merchant, print: "Items in stock: [StoreInventoryCount]"
  • If the NPC is neither, print: "Hello there, traveler!"

Then, create a list containing one of each NPC type and loop through them, calling InteractWithNPC for each one to ensure your logic handles all types without crashing.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.