4P by GN⁺ 6일전 | ★ favorite | 댓글 3개
  • .NET 10 Preview 4부터는, 이제 단일 C# 파일을 dotnet run app.cs로 바로 실행할 수 있는 기능이 추가되어, 프로젝트 파일 없이도 C# 코드 실행이 가능해짐
  • 파일 기반 앱(file-based apps) 덕분에, Python이나 JavaScript처럼 간단한 스크립트 실행, 테스트, 아이디어 실험이 한층 쉬워짐
  • NuGet 패키지 참조, SDK 지정, 빌드 속성 설정 등도 파일 내 디렉티브로 관리할 수 있어 개발 유연성이 향상
  • shebang 지원으로 유닉스 계열에서 CLI 유틸리티, 자동화 스크립트 등에도 활용 가능
  • 필요시 프로젝트 기반 앱으로 매끄럽게 변환 가능해, 학습 및 프로토타입에서 본격적인 앱 개발까지 자연스럽게 연계됨

dotnet run app.cs란 무엇인가

  • 기존에는 dotnet CLI로 C# 코드를 실행하려면 반드시 프로젝트(.csproj) 구조가 필요했음
  • 이제는 단일 .cs 파일만으로 바로 실행 가능하여, 진입 장벽이 크게 낮아짐
  • 스크립트 언어나 자동화, 실험, 학습 등 다양한 용도에 적합함
  • CLI 통합으로 추가 도구 설치 없이 dotnet만 있으면 바로 사용 가능함
  • 코드가 커지면 동일한 언어와 도구로 프로젝트 기반 앱으로 확장 가능함

파일 수준 디렉티브 지원

  • 파일 기반 앱에서도 프로젝트의 주요 설정들을 직접 .cs 파일 내에 디렉티브로 선언할 수 있음
  • NuGet 패키지 참조

    • #:package 디렉티브로 NuGet 패키지를 바로 참조할 수 있음
      • 예시:
        #:package Humanizer@2.14.1  
        
        using Humanizer;  
        
        var dotNet9Released = DateTimeOffset.Parse("2024-12-03");  
        var since = DateTimeOffset.Now - dotNet9Released;  
        
        Console.WriteLine($"It has been {since.Humanize()} since .NET 9 was released.");  
        
  • SDK 지정

    • #:sdk 디렉티브로 SDK 종류 지정 가능
      • 예시:
        #:sdk Microsoft.NET.Sdk.Web  
        
      • ASP.NET Core 기능(최소 API, MVC 등)도 활성화 가능
  • MSBuild 속성 설정

    • #:property로 빌드 속성 직접 지정 가능
      • 예시:
        #:property LangVersion preview  
        
  • 쉘 스크립트용 shebang 지원

    • 파일 맨 위에 #!/usr/bin/dotnet run을 넣어, 유닉스 계열에서 실행 파일로 바로 사용할 수 있음
      • 예시:
        #!/usr/bin/dotnet run  
        Console.WriteLine("Hello from a C# script!");  
        
      • 실행 권한 부여 후 바로 실행:
        chmod +x app.cs  
        ./app.cs  
        

프로젝트 기반 앱으로의 변환

  • 앱이 커지거나 더 많은 기능이 필요할 때, dotnet project convert app.cs 명령어로 프로젝트로 손쉽게 변환 가능
  • 디렉티브는 .csproj 파일 속성, 참조 등으로 자동 변환됨
  • 변환 예시

    • 아래와 같은 파일:
      #:sdk Microsoft.NET.Sdk.Web  
      #:package Microsoft.AspNetCore.OpenApi@10.*-*  
      
      var builder = WebApplication.CreateBuilder();  
      builder.Services.AddOpenApi();  
      var app = builder.Build();  
      app.MapGet("/", () => "Hello, world!");  
      app.Run();  
      
    • 변환 결과:
    <Project Sdk="Microsoft.NET.Sdk.Web">  
      <PropertyGroup>  
        <TargetFramework>net10.0</TargetFramework>  
        <ImplicitUsings>enable</ImplicitUsings>  
        <Nullable>enable</Nullable>  
      </PropertyGroup>  
      <ItemGroup>  
        <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.*-*" />  
      </ItemGroup>  
    </Project>  
    

기존 C# 스크립트 방식과의 차이

  • 그동안 커뮤니티 툴(CS-Script, dotnet-script, Cake 등)로 C# 스크립트 실행이 가능했지만, 별도 도구 설치와 설정 필요
  • 이제는 별도 설치나 모드 없이 동일한 C# 컴파일러와 언어를 사용해, 진입 장벽 없이 바로 코드 실행 가능

시작 방법

  • .NET 10 Preview 4 설치
  • Visual Studio Code 사용 시, C# Dev Kit최신 프리릴리즈 버전의 C# 확장(2.79.8 이상) 설치 필요
  • .cs 파일 생성 후 바로 코드 작성
  • 터미널에서 dotnet run hello.cs 실행
  • 필요시 dotnet project convert hello.cs로 프로젝트로 변환

더 알아보기

향후 계획

  • VS Code 내 파일 기반 앱 지원디렉티브용 IntelliSense 향상, 성능 개선, 디버깅 지원 강화 예정
  • 다중 파일 지원과 실행 속도 개선 등 추가 기능도 개발 중
  • dotnet run app.cs는 C#을 더욱 쉽게 접근할 수 있게 하면서, .NET의 강력함을 그대로 제공함
  • 프로토타이핑, 교육, 프로덕션 개발까지 더 빠르게 전환할 수 있는 기반 제공

전에 C# Interactive 기능을 사용했을 때 로컬에 설치되지 않은 패키지는 사용할 수가 없었는데 이제 개선이 되었나 보네요.

Hacker News 의견
  • 이 기능이 .NET 개발자 생산성에 큰 영향을 줄 수 있을 것 같아 아쉬움도 생기는 부분, 왜 이제서야 나왔는지 궁금함, 그리고 .NET 프로젝트에서 정말 바라는 기능이 하나 있는데, 프로젝트별로 쉽게 커스텀 커맨드를 정의할 수 있는 기능임, 예를 들어 "npm run <command>" 같은 방식이 있으면 좋겠음
  • 이걸 shebang과 함께 적극적으로 활용하라고 홍보하는 게 흥미로움, 이런 접근이 꽤 매력적으로 느껴짐, Go가 모듈 도입 전에도 이런 식으로 스크립팅 쓰임새가 좋았고, Ubuntu도 이런 식으로 사용한 걸로 기억함, 하지만 Go 저자들은 Go를 이런 스크립팅 언어로 쓰는 방식에는 부정적 입장이었음
    • Go 저자들이 반대한 게 아니라, Go를 우선적으로 프로그래밍 언어로 사용하길 권장했다는 설명임, gorun (https://github.com/erning/gorun) 같은 툴로 예전부터 쉽게 Go를 스크립트처럼 쓸 수 있었음, 최근에는 이걸 한 번에 실행할 수 있도록 go run github.com/kardianos/json/cmd/jsondiff@v1.0.1처럼 태그를 바로 받아 실행하게 지원함, 이거 꽤 멋진 기능임
    • ‘shebang’이란 말을 어디서부터, 언제부터 썼는지 궁금함, 대학 다닐 때랑 90~2000년대 초 남부 지역에서는 보통 hashbang이라고 불렀음, shebang은 C#이 유행하면서 처음 들었고, 실제로는 더 이전부터 있었던 용어임, 다만 주변에선 못 들어봤던 단어임
    • 예전에 .NET 회사에서 일할 때, 누구는 갑자기 bash로 오토메이션 스크립트를 짜기도 했었음, 이런 스크립트를 장기적으로 관리할 전문성이 없었고, 처음 쓸 때부터 퀄리티도 별로였음, 왜 그냥 도구 자체를 C#으로 만들지 않았는지 이해가 안 갔었음, 이번 기능 덕분에 C# 접근이 훨씬 실제적 대안으로 느껴질 수도 있을 것 같음
    • Rust의 cargo로도 이런 게 가능함, 다만 아직 정식 지원은 아님 https://rust-lang.github.io/rfcs/3424-cargo-script.html
  • 기능 자체는 훌륭하지만, 컴파일된 상태라 하더라도 스타트업 오버헤드가 약 0.5초 정도 걸림, 그래서 많은 애플리케이션에서 적합하지 않다는 단점이 있음, 그래도 bash에 의존하는 쉘 스크립팅의 한계도 있고, perl 시대는 이미 지났고, Ruby가 여전히 이런 용도엔 최고라서 계속 써 왔었음, 최근엔 Swift로 몇몇 스크립트를 옮겼는데 기본적으로 인터프리터 방식이라서 훨씬 빠르고, 컴파일된 실행 파일은 바로 실행되기 때문에 매우 인상적임, Swift CLI 앱을 위한 캐싱 컴파일러도 직접 만들어 봤음(https://github.com/jrz/tools), 참고로 dotnet run은 이미 컴파일 결과를 캐시해주기 때문에 별도의 캐싱 레이어가 필요 없음(비활성화하려면 --no-build, 바이너리 경로 확인하려면 --artifacts-path 사용)
    • 0.5초라는 수치가 어디 정보인지 궁금함, 나는 hello world로 테스트했더니 63ms 나왔음, neuecc의 CLI 라이브러리 벤치마크(https://neuecc.medium.com/consoleappframework-v5-zero-overhead-native-…)를 보면 그 어떤 것도 0.5초에 도달하지 않음, 참고로 Swift가 기본적으론 인터프리터 방식이라는 점을 언급했는데, .NET JIT는 티어드 JIT라서 바로 코드가 만들어지지 않고 여러 단계로 진행되는 구조임
    • dotnet도 10 혹은 11 버전에서 완전한 인터프리티드 모드가 도입될 예정이라고 들음, 이런 용도에 해당 모드가 적용될지도 궁금함 https://github.com/dotnet/runtime/issues/112748
    • 컴파일되어도 스타트업에 약간 랙이 있으면 왜 python은 이런 영역에서 큰 인기를 얻었는지 궁금함
    • 이 기능이 아직 초반 프리뷰 단계임, 여러 발표에서 스타트업 속도 이슈는 인지하고 있고 개선 중임을 밝혔었음
    • 빠른 스타트업을 원한다면 https://learn.microsoft.com/en-us/dotnet/core/deploying/ 안내대로 쉽게 네이티브 코드로 변환할 수 있음
  • CSX/VBX 프로젝트에 대한 언급이 부족해서 아쉬움 https://ttu.github.io/dotnet-script/, C# 런타임에서 F# 스크립트의 의존성 처리와도 호환되지 않는 방식으로 결정한 것 같아 신기함 https://learn.microsoft.com/en-us/dotnet/…
    • CSX/VBX 등의 노력이 반영되지 않았다는 얘기에 대해, 실제로 공식적으로 여러 방식과 툴이 언급되어 있다는 점을 안내함 https://devblogs.microsoft.com/dotnet/announcing-dotnet-run-app/…
    • F#과 비호환적이라는 부분이 무슨 의미인지 질문, 문법 차이 얘기라면, 문법을 의도적으로 다르게 만든 목적이 있었고, C# 스크립트 다이얼렉트 신설을 원치 않았기에 파일 import 같은 기능을 일부러 막음, 이건 C# 특성 때문임
  • Kotlin에서도 비슷한 기능이 존재, https://github.com/Kotlin/kotlin-script-examples/… (여기선 파일 확장자가 반드시 "*.main.kts"이어야 동작함), 이런 방식은 작은 스크립트나 프로토타이핑에 아주 좋고, JVM 기능을 활용하는 데도 실용적임, 그래도 작은 스크립트엔 Ruby가 여전히 가장 편함, 특히 외부 프로그램 실행할 때 backtick 문법이 정말 편리함
    • Kotlin 스크립트가 완전히 사라지진 않겠지만, 미래가 그렇게 밝지는 않음 https://blog.jetbrains.com/kotlin/2024/…
    • Java 자체에도 유사한 스크립트 방식이 생긴 걸로 알고 있음
  • shebang을 이용해서 C# 스크립트를 bash 스크립트처럼 실행할 수 있음 https://devblogs.microsoft.com/dotnet/announcing-dotnet-run-app/…
    • .net10 preview 4 sdk 이미지에서 파일을 직접 실행하려고 shebang을 테스트했으나 처음엔 잘 안 됐음, dotnet run <file>로는 동작, 업데이트 후엔 정상 동작, 문제 원인은 파일이 LF가 아니라 CRLF 줄바꿈 사용함 때문이었음
    • 이제 타입 세이프티가 적용된 스크립트를 작성할 수 있게 된 점이 매우 반가움, 참고로 macOS에서는 shebang에 #!/usr/local/share/dotnet/dotnet run 혹은 #!/usr/bin/env -S dotnet run을 써야 함
  • PowerShell을 대체할 만한 도구로 보임, PowerShell은 거의 ChatGPT 전용 언어처럼 쓰이는 경향도 있음, 대부분의 회사에서 PowerShell로 작성된 스크립트가 인프라 핵심 역할을 하지만, 사실상 ‘읽기 전용’ 상태에 빠지는 경우가 많음
    • PowerShell뿐 아니라 훨씬 더 넓은 영역까지 대체할 수 있는 잠재력이 느껴짐, .NET 팀이라면 굳이 Python이나 shell 스크립트에 손 댈 필요 없이, 상단에 shebang 추가해서 C# 스니펫 붙여넣기만 해도 거의 모든 스크립트 처리가 가능해질 수 있을 듯, 테스트 서비스도 굳이 express.js로 짤 필요 없이, ASP.NET minimal API로 쓱 만들면 끝
    • 윈도우 시스템 관리자들이 아마 가장 대규모 ChatGPT 스크립트를 쓰는 집단 아닐까 싶음, 나도 예전 관리자였다면, MS 공식 문서 수준 감안해서라면 반드시 써봤을 것 같음
    • C# 코드를 PowerShell에서 호출하는 것도 가능함 https://learn.microsoft.com/en-us/powershell/…
    • PowerShell로 모든 인프라를 스크립트로 넣는 건 실제로 쉽지 않고, 그렇게 하면 대혼돈이 발생할 뿐임, 실제로 함수 몇 개 이상 넘어가면 C#이 훨씬 효율적이고 진입장벽도 거의 없음, PowerShell은 소규모 ad-hoc 스크립트엔 최적이고, 예전 VBScript 같은 ‘윈도우 기본 스크립트 언어’ 자리를 차지하고 있음
    • PowerShell이 .NET 코드를 직접 돌릴 수 있기 때문에, 오히려 PowerShell 경험이 확장되는 면도 보임
  • NetPad 기능을 사실상 대체하는 것 같고, 디버깅만 추가되면 LINQPad도 현역에서 밀려날 것 같은 예감, 나도 예전엔 LINQPad 덕을 참 많이 봤지만, 아직도 텍스트 에디터 경험은 지금 시대엔 너무 불편함, 본격적인 코드 작성이나 편집용으로 쓰기엔 한계가 큼
    • 내 경우 LINQPad의 핵심 사용처는 DB 상호작용이나 .dump()로 값을 탐색하는 용도임, 이번 dotnet run은 오히려 그걸 보완해주는 도구로 쓸 수 있을 듯, 예전에 PowerShell을 극도로 싫어하는 곳에서 LINQPad로 거의 모든 스크립팅을 처리했었는데, 그런 현장에서는 쓸 만했음
    • LINQPad는 .NET에선 유니크한 제품이지만, 텍스트 에디터 자체는 역대 최악에 가까울 때가 많음, neovim이나 monaco 같은 에디터로 교체되면 좋겠음, 테이블 시각화나 snappiness 같은 건 참 좋은데, 요즘 Jupyter Notebook 등 ‘노트북’ 기술에 비하면 활용의 폭은 좁아짐, 단독 개발자라 그 한계도 있는 듯함, 그래도 매일 실무에서 SQL 데이터 만질 때 LINQPad는 여전히 최고임
    • LINQPad가 바로 대체되진 않을 듯, 절반의 경쟁력은 UI에 있다고 생각, VSCode나 Visual Studio에서 dotnet run 사용 경험이나 LINQPad랑 얼마나 비슷할지 궁금함, LINQPad는 결과값을 시각화하는 기능이 강점임, dotnet run이 텍스트만 뿌리거나 별도 플러그인이 많이 필요하면 LINQPad 수요는 계속될 듯, 문법 확인 등만 필요하다면 dotnet run이 더 나은 선택일 수 있음, 나도 가끔 헷갈리는 문법은 LINQPad로 실험해봄
    • GUI 기능, 확장포인트까지 모두 구현하지 않는 한 LINQPad 바로 대체는 어려울 듯
  • 이 기능 진심 기대됨, 내가 CI/CD 파이프라인에서 쓰는 PowerShell 스크립트 일부를 대체할 수 있을 것 같음, PowerShell과 Bash 모두 좋아하지만, 머릿속에서 C 계열 문법 언어로 푸는 게 훨씬 효율적인 작업이 분명히 있음, 이번 기능이 그런 공백을 메워줄 수 있을 듯함
  • 실제 제안문(https://github.com/dotnet/sdk/…)에 여러 정보가 더 들어가 있음, 특히 여러 파일 처리라든가, 구현 세부사항(암시적 프로젝트 파일 등)에 대해 자세히 설명함

이 기능과 관련된 실제 예제 2개를 만들어본것도 있어 답글로 공유합니다. MCP 서버와 Avalonia를 이용한 Windows, macOS GUI 앱 샘플 코드입니다. 😊

https://forum.dotnetdev.kr/t/…