3 min read

Resolving Namespace Shadowing in .Net Core

Namespace shadowing in C# occurs when a namespace and a class share the same name, causing compiler error CS0118. This article explains why it happens, how C# resolves namespaces, and shows practical fixes using imports, fully qualified names, aliases, and Razor configuration.
Resolving Namespace Shadowing in .Net Core

Overview

Namespace shadowing occurs when a namespace and a type share the same name, causing the C# compiler to prioritize the namespace and fail to resolve the type. This article provides solutions for the common error: CS0118: '[Name]' is a namespace but is used like a type.

Understanding the Problem

Namespace Resolution Order

C# resolves names in the following order:

  1. Current namespace
  2. Imported namespaces (using directives)
  3. Parent namespaces

Common Scenario

MyPhotoBiz/
├── Models/
│   └── PhotoShoot/              # Creates namespace: MyPhotoBiz.Models.PhotoShoot
│       └── PhotoShoot.cs        # Contains class: PhotoShoot
└── ViewModels/
    └── DashboardViewModel.cs

When DashboardViewModel.cs contains:

using MyPhotoBiz.Models;

public class DashboardViewModel
{
    public List<PhotoShoot> RecentPhotoShoots { get; set; }  // Error CS0118
}

The compiler sees MyPhotoBiz.Models.PhotoShoot (namespace) before finding the PhotoShoot class within it.

Solutions

Solution 1: Import Specific Namespace

Import the exact namespace containing the type:

using MyPhotoBiz.Models.PhotoShoot;  // Import the inner namespace

public class DashboardViewModel
{
    public List<PhotoShoot> RecentPhotoShoots { get; set; }  // Resolves correctly
}

Solution 2: Use Fully Qualified Names

Reference types with their complete namespace path:

public class DashboardViewModel
{
    public List<MyPhotoBiz.Models.PhotoShoot.PhotoShoot> RecentPhotoShoots { get; set; }
}

Solution 3: Type Aliases

Create a type alias to simplify references:

using PhotoShootModel = MyPhotoBiz.Models.PhotoShoot.PhotoShoot;

public class DashboardViewModel
{
    public List<PhotoShootModel> RecentPhotoShoots { get; set; }
}

Solution 4: Global Using Directives (C# 10+)

Create a GlobalUsings.cs file:

global using MyPhotoBiz.Models.PhotoShoot;
global using MyPhotoBiz.ViewModels.Dashboard;
global using MyPhotoBiz.ViewModels.Invoices;

Solution 5: Razor Views Configuration

In Views/_ViewImports.cshtml, add specific namespace imports:

@using MyPhotoBiz
@using MyPhotoBiz.Models
@using MyPhotoBiz.Models.PhotoShoot
@using MyPhotoBiz.ViewModels.Dashboard
@using MyPhotoBiz.ViewModels.PhotoShoot
@using MyPhotoBiz.ViewModels.Albums
@using MyPhotoBiz.ViewModels.Invoices
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Then in Razor views:

@model PhotoShootViewModel  // Short name works with _ViewImports

Fixing Razor View Errors

When Razor views generate namespace errors, update the @model directive:

Before (Incorrect)

@model MyPhotoBiz.ViewModels.PhotoShootViewModel

After (Correct)

@model MyPhotoBiz.ViewModels.PhotoShoot.PhotoShootViewModel

Batch Fix with Find and Replace

Use regular expressions in your editor:

Find: @model MyPhotoBiz\.ViewModels\.(\w+)ViewModel Replace: @model MyPhotoBiz.ViewModels.$1.$1ViewModel

Or individual replacements:

Find

Replace

@model MyPhotoBiz.ViewModels.DashboardViewModel

@model MyPhotoBiz.ViewModels.Dashboard.DashboardViewModel

@model MyPhotoBiz.ViewModels.PhotoShootViewModel

@model MyPhotoBiz.ViewModels.PhotoShoot.PhotoShootViewModel

@model MyPhotoBiz.ViewModels.AlbumViewModel

@model MyPhotoBiz.ViewModels.Albums.AlbumViewModel

Best Practices

Avoid Name Collisions

Not Recommended:

Models/
└── PhotoShoot/          # Namespace matches class name
    └── PhotoShoot.cs

Recommended:

Models/
└── PhotoShoot/
    └── PhotoShootEntity.cs    # Different class name

# OR use flat structure
Models/
└── PhotoShoot.cs        # Namespace: Models, Class: PhotoShoot

Namespace Naming Conventions

  1. Plural for collections: Models.PhotoShoots for multiple model files
  2. Singular for single files: Models.PhotoShoot.cs in flat structure
  3. Descriptive suffixes: PhotoShootEntity, PhotoShootModel, PhotoShootDto

Project Organization

MyPhotoBiz/
├── Models/              # Flat structure OR
│   ├── Client.cs
│   ├── PhotoShoot.cs
│   └── Invoice.cs
├── ViewModels/          # Organized by feature
│   ├── Dashboard/
│   │   └── DashboardViewModel.cs
│   ├── PhotoShoots/     # Plural to avoid conflict
│   │   ├── CreatePhotoShootViewModel.cs
│   │   └── EditPhotoShootViewModel.cs
│   └── Invoices/
│       └── InvoiceViewModel.cs

Tooling and Automation

Visual Studio Code Extensions

  1. C# Dev Kit (ms-dotnettools.csdevkit)
    • Auto-imports namespaces
    • Quick fixes with Ctrl+. (Cmd+. on Mac)
  2. C# Namespace Autocompletion (adrianwilczynski.namespace)
    • Generates correct namespaces from folder structure
  3. C# Extensions (kreativ-software.csharpextensions)
    • Organize usings command

Command Line Tools

# Install dotnet-format globally
dotnet tool install -g dotnet-format

# Format entire project
dotnet format

# Format specific file
dotnet format --include path/to/file.cs

IDE Quick Actions

In Visual Studio or VS Code with C# extensions:

  1. Click on the error indicator
  2. Press Ctrl+. or click the lightbulb icon
  3. Select "using [namespace]" or "Qualify name"

Troubleshooting

Error Persists After Adding Using Directive

Check: Ensure you're importing the innermost namespace:

using MyPhotoBiz.Models;           // ✗ Too general
using MyPhotoBiz.Models.PhotoShoot;  // ✓ Specific

Multiple Types with Same Name

Use aliases to differentiate:

using DomainPhotoShoot = MyPhotoBiz.Domain.PhotoShoot;
using ViewModelPhotoShoot = MyPhotoBiz.ViewModels.PhotoShoot.PhotoShootViewModel;

Razor Views Not Recognizing Types

  1. Verify _ViewImports.cshtml is in the correct location
  2. Check that namespace in _ViewImports.cshtml matches your file structure
  3. Rebuild the project to regenerate Razor view compilation

Migration Strategy

For existing projects with namespace conflicts:

Step 1: Identify Conflicts

# Search for namespace errors
dotnet build 2>&1 | grep "CS0118"

Step 2: Create Mapping Document

Old Structure          → New Structure
Models.PhotoShoot      → Models.PhotoShoot.PhotoShootEntity
ViewModels.Invoice     → ViewModels.Invoices.InvoiceViewModel

Step 3: Refactor Systematically

  1. Update file names
  2. Update namespace declarations
  3. Update all references
  4. Update Razor views
  5. Run tests

Step 4: Verify

dotnet build
dotnet test

Summary

Problem: Namespace names matching type names cause CS0118 errors.

Primary Solutions:

  1. Import specific namespaces: using MyApp.Models.TypeName;
  2. Use fully qualified names in code
  3. Configure _ViewImports.cshtml for Razor views
  4. Apply consistent naming conventions to prevent conflicts

Prevention:

  • Avoid naming folders the same as classes within them
  • Use plural folder names for collections
  • Implement global usings for frequently used namespaces
  • Leverage IDE tools for namespace management