본문 바로가기

C#

C# 파일 스코프 네임스페이스(File-Scoped Namespace) 활용

C# 10부터 도입된 파일 스코프 네임스페이스는 세미콜론(;) 하나로 파일 전체에 적용되는 네임스페이스를 선언하는 문법입니다. 중괄호와 불필요한 들여쓰기를 제거해 가독성을 높이고, 대규모 코드베이스에서 코드 리뷰와 머지를 쉽게 합니다.

1. 문법 한눈에 보기

기존 블록 스코프 네임스페이스와 파일 스코프 네임스페이스의 차이를 비교합니다.

기존(블록 스코프)입니다.

namespace Contoso.Utilities
{
    public static class StringExtensions
    {
        public static bool IsNullOrWhite(this string? s) => string.IsNullOrWhiteSpace(s);
    }

    internal sealed class Slugifier
    {
        public string ToSlug(string text) => text
            .ToLowerInvariant()
            .Replace(' ', '-');
    }
}

파일 스코프입니다.

namespace Contoso.Utilities;

public static class StringExtensions
{
    public static bool IsNullOrWhite(this string? s) => string.IsNullOrWhiteSpace(s);
}

internal sealed class Slugifier
{
    public string ToSlug(string text) => text
        .ToLowerInvariant()
        .Replace(' ', '-');
}

효과는 동일하며, 들여쓰기가 한 단계 줄어 전체 가독성이 좋아집니다.

2. 중첩 네임스페이스 표현

파일 스코프 네임스페이스는 중첩 블록을 지원하지 않습니다. 대신 점(.)을 사용해 한 번에 전체 경로를 선언합니다.

// 권장: 점 표기 사용
namespace Contoso.Tools.Parsing;

public sealed class Tokenizer { }

3. 파일 내 배치 규칙과 주의사항

아래 규칙을 지키면 빌드 오류를 피할 수 있습니다.

  • 한 파일에는 하나의 파일 스코프 네임스페이스만 선언합니다.
  • global using, extern alias, using 지시문, 파일 수준 특성은 네임스페이스 선언보다 위에 둡니다.
  • 파일 스코프와 블록 스코프 네임스페이스를 같은 파일에서 섞지 않습니다.
  • Top-level statements는 네임스페이스 내부에 둘 수 없습니다. 같은 파일에서 파일 스코프 네임스페이스와 함께 사용하지 않습니다.
  • partial 타입이 여러 파일에 흩어져 있다면, 모든 파일에서 동일한 네임스페이스를 사용해야 합니다.

파일 수준 특성을 사용하는 예입니다.

using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("Contoso.Tests")]

namespace Contoso.Core;

public sealed class Foo { }

4. 팀에 적용하는 방법(.editorconfig/IDE/CLI)

에디터에서 자동으로 파일 스코프를 권장하도록 설정합니다.

# .editorconfig
[*.cs]
csharp_style_namespace_declarations = file_scoped:suggestion
# "파일 스코프 네임스페이스로 변환" 진단 강도 조정(Roslyn: IDE0161)
dotnet_diagnostic.IDE0161.severity = warning

IDE에서 변환합니다.

  • Visual Studio/Rider: 네임스페이스 선언에서 빠른 작업(Alt+Enter) → "파일 스코프 네임스페이스로 변환"을 적용합니다.
  • 솔루션 전체 일괄 적용: 솔루션 탐색기에서 상위 노드 선택 → 빠른 작업/리팩터링 → 문서/프로젝트 범위 적용을 선택합니다.

CLI로 스타일을 적용합니다.

# .editorconfig 기반 스타일 진단 적용
# .NET 6+ SDK 기준
dotnet format style --severity warn --diagnostics IDE0161

5. 실전 예시: 라이브러리/확장 메서드

여러 타입을 한 파일에 두어도 들여쓰기가 늘지 않습니다.

namespace Contoso.Text;

public static class SlugExtensions
{
    public static string ToSlug(this string text)
        => text.Trim().ToLowerInvariant().Replace(' ', '-');
}

internal sealed class SlugValidator
{
    public bool IsValid(string slug) => !string.IsNullOrWhiteSpace(slug) && !slug.Contains(' ');
}

ASP.NET Core 확장 클래스도 간결해집니다.

using Microsoft.Extensions.DependencyInjection;

namespace Contoso.Web;

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddContoso(this IServiceCollection services)
    {
        // 등록 로직
        return services;
    }
}

6. 마이그레이션 팁

  • PR 단위를 작게 나눠 모듈/프로젝트별로 점진 적용합니다.
  • 변환 후 네임스페이스 경로가 동일한지 확인합니다(특히 partial/InternalsVisibleTo 사용 시).
  • 코드 생성기나 소스 제너레이터 출력은 도구가 지원하는지 확인합니다.

7. 자주 묻는 질문

  • 바이너리 호환이 달라지나요? 타입의 정규 네임스페이스가 같다면 IL 출력은 동일합니다.
  • 성능 차이가 있나요? 컴파일러 처리 관점에서 성능 차이는 사실상 없습니다. 스타일 선택입니다.
  • 중첩 네임스페이스가 많은 프로젝트에 유리한가요? 점 표기로 표현해도 의미가 동일하며, 들여쓰기가 줄어 유리합니다.

정리하면, 파일 스코프 네임스페이스는 C# 10 시대의 기본 코드 스타일입니다. .editorconfig와 도구를 통해 일관되게 적용해 보시기 바랍니다.