Menu

How to Use is and as Keywords for Type Checking in C#

Type checking and conversion are essential operations in C#'s object-oriented programming model.

The is and as keywords provide elegant solutions for safely working with types at runtime. Understanding when and how to use each can significantly improve your code's robustness and readability.

The is Operator: Type Checking

The is operator evaluates whether an object is compatible with a given type, returning a boolean result.

Basic Usage

object value = "Hello, World!";

// Check if value is a string
if (value is string)
{
    Console.WriteLine("value is a string");
}

Pattern Matching (C# 7.0+)

// Type checking with declaration
if (value is string message)
{
    // message is now a string variable containing the value
    Console.WriteLine($"Length: {message.Length}");
}

Type Patterns with Conditions (C# 9.0+)

// Check type and condition in one step
if (value is string { Length: > 5 } longString)
{
    Console.WriteLine($"Long string found: {longString}");
}

The as Operator: Safe Casting

The as operator attempts to cast an object to a specified reference type, returning null if the cast fails rather than throwing an exception.

Basic Usage

object value = "Hello, World!";

// Try to cast to string
string message = value as string;

// Check if cast was successful
if (message != null)
{
    Console.WriteLine($"Successful cast: {message}");
}

Important Limitations

  • The as operator only works with reference types and nullable value types
  • It cannot be used with non-nullable value types (use is with pattern matching instead)

Choosing Between is and as

Scenario Recommended Approach
Just checking type Use is
Checking type and using the object Use is with pattern matching
Possibly working with a null result Use as
Working with value types Use is (with pattern matching if needed)
Multiple operations on same cast Use as once, then check for null

Best Practices

  1. Prefer pattern matching with is when you need both type checking and casting
  2. Use as when working with hierarchies where null is a valid outcome
  3. Avoid as followed by null checking when is pattern matching works
  4. Remember that as never throws exceptions, while direct casting can
  5. Consider extension methods as an alternative to frequent type checking

Understanding these operators helps you write more elegant, safe code when working with polymorphic types in C#.

0
55

Related

Closing a SqlDataReader correctly prevents memory leaks, connection issues, and unclosed resources. Here’s the best way to do it.

Use 'using' to Auto-Close

Using using statements ensures SqlDataReader and SqlConnection are closed even if an exception occurs.

Example

using (SqlConnection conn = new SqlConnection(connectionString))
{
    conn.Open();
    using (SqlCommand cmd = new SqlCommand("SELECT * FROM Users", conn))
    using (SqlDataReader reader = cmd.ExecuteReader())
    {
        while (reader.Read())
        {
            Console.WriteLine(reader["Username"]);
        }
    } // ✅ Auto-closes reader here
} // ✅ Auto-closes connection here

This approach auto-closes resources when done and it is cleaner and less error-prone than manual closing.

⚡ Alternative: Manually Close in finally Block

If you need explicit control, you can manually close it inside a finally block.

SqlDataReader? reader = null;
try
{
    using SqlConnection conn = new SqlConnection(connectionString);
    conn.Open();
    using SqlCommand cmd = new SqlCommand("SELECT * FROM Users", conn);
    reader = cmd.ExecuteReader();

    while (reader.Read())
    {
        Console.WriteLine(reader["Username"]);
    }
}
finally
{
    reader?.Close();  // ✅ Closes reader if it was opened
}

This is slightly more error prone if you forget to add a finally block. But might make sense when you need to handle the reader separately from the command or connection.

1
209

Reading a file line by line is useful when handling large files without loading everything into memory at once.

✅ Best Practice: Use File.ReadLines() which is more memory efficient.

Example

foreach (string line in File.ReadLines("file.txt"))
{
    Console.WriteLine(line);
}

Why use ReadLines()?

Reads one line at a time, reducing overall memory usage. Ideal for large files (e.g., logs, CSVs).

Alternative: Use StreamReader (More Control)

For scenarios where you need custom processing while reading the contents of the file:

using (StreamReader reader = new StreamReader("file.txt"))
{
    string? line;
    while ((line = reader.ReadLine()) != null)
    {
        Console.WriteLine(line);
    }
}

Why use StreamReader?

Lets you handle exceptions, encoding, and buffering. Supports custom processing (e.g., search for a keyword while reading).

When to Use ReadAllLines()? If you need all lines at once, use:

string[] lines = File.ReadAllLines("file.txt");

Caution: Loads the entire file into memory—avoid for large files!

4
329

In C#, you can format an integer with commas (thousands separator) using ToString with a format specifier.

int number = 1234567;
string formattedNumber = number.ToString("N0"); // "1,234,567"
Console.WriteLine(formattedNumber);

Explanation:

"N0": The "N" format specifier stands for Number, and "0" means no decimal places. The output depends on the culture settings, so in regions where , is the decimal separator, you might get 1.234.567.

Alternative:

You can also specify culture explicitly if you need a specific format:

using System.Globalization;

int number = 1234567;
string formattedNumber = number.ToString("N0", CultureInfo.InvariantCulture);
Console.WriteLine(formattedNumber); // "1,234,567"
4
511