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:
- Current namespace
- Imported namespaces (using directives)
- Parent namespaces
Common Scenario
MyPhotoBiz/
├── Models/
│ └── PhotoShoot/ # Creates namespace: MyPhotoBiz.Models.PhotoShoot
│ └── PhotoShoot.cs # Contains class: PhotoShoot
└── ViewModels/
└── DashboardViewModel.csWhen 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.TagHelpersThen in Razor views:
@model PhotoShootViewModel // Short name works with _ViewImportsFixing Razor View Errors
When Razor views generate namespace errors, update the @model directive:
Before (Incorrect)
@model MyPhotoBiz.ViewModels.PhotoShootViewModelAfter (Correct)
@model MyPhotoBiz.ViewModels.PhotoShoot.PhotoShootViewModelBatch 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 |
|---|---|
|
|
|
|
|
|
Best Practices
Avoid Name Collisions
Not Recommended:
Models/
└── PhotoShoot/ # Namespace matches class name
└── PhotoShoot.csRecommended:
Models/
└── PhotoShoot/
└── PhotoShootEntity.cs # Different class name
# OR use flat structure
Models/
└── PhotoShoot.cs # Namespace: Models, Class: PhotoShootNamespace Naming Conventions
- Plural for collections:
Models.PhotoShootsfor multiple model files - Singular for single files:
Models.PhotoShoot.csin flat structure - 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.csTooling and Automation
Visual Studio Code Extensions
- C# Dev Kit (
ms-dotnettools.csdevkit)- Auto-imports namespaces
- Quick fixes with Ctrl+. (Cmd+. on Mac)
- C# Namespace Autocompletion (
adrianwilczynski.namespace)- Generates correct namespaces from folder structure
- 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.csIDE Quick Actions
In Visual Studio or VS Code with C# extensions:
- Click on the error indicator
- Press
Ctrl+.or click the lightbulb icon - 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; // ✓ SpecificMultiple Types with Same Name
Use aliases to differentiate:
using DomainPhotoShoot = MyPhotoBiz.Domain.PhotoShoot;
using ViewModelPhotoShoot = MyPhotoBiz.ViewModels.PhotoShoot.PhotoShootViewModel;Razor Views Not Recognizing Types
- Verify
_ViewImports.cshtmlis in the correct location - Check that namespace in
_ViewImports.cshtmlmatches your file structure - 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.InvoiceViewModelStep 3: Refactor Systematically
- Update file names
- Update namespace declarations
- Update all references
- Update Razor views
- Run tests
Step 4: Verify
dotnet build
dotnet testSummary
Problem: Namespace names matching type names cause CS0118 errors.
Primary Solutions:
- Import specific namespaces:
using MyApp.Models.TypeName; - Use fully qualified names in code
- Configure
_ViewImports.cshtmlfor Razor views - 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