Microsoft MVP성태의 닷넷 이야기
.NET Framework: 258. Roslyn 맛보기 - SyntaxTree 조작 [링크 복사], [링크+제목 복사]
조회: 18780
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 6개 있습니다.)

Roslyn 맛보기 - SyntaxTree 조작


Roslyn 맛보기 (1) - C# 소스 코드를 스크립트 처럼 다루는 방법
Roslyn 맛보기 (2) - C# Interactive (1)
Roslyn 맛보기 (3) - C# Interactive (2)
Roslyn 맛보기 (4) - Roslyn Services APIs를 이용한 Code Issue 및 Code Action 기능 소개
Roslyn 맛보기 (5) - Syntax Analysis (Roslyn Syntax API)
Roslyn 맛보기 (6) - Roslyn Symbol / Binding API
Roslyn 맛보기 (7) - SyntaxTree 조작

드디어 마지막 이야기까지 왔군요. ^^

이번 글은, "%PROGRAMFILES% (x86)\Microsoft Codename Roslyn CTP\Getting Started - Syntax Transformation (CSharp).docx" 파일(현재는 "Get started with syntax transformation" 자료로 제공)을 요약한 것이라고 보면 됩니다.




이전에 언급했던 것처럼, SyntaxTree는 immutable이므로 변경을 가하는 경우 새롭게 생성된 별개의 SyntaxTree 인스턴스가 반환이 됩니다. 그래서인지, 변경 메서드 자체도 set ... 류가 아닌 replace ... 류입니다.

Replace를 해야 하기 때문에 교체될 노드를 새롭게 생성하는 방법이 필요한데요. 이러한 목적으로 Syntax API에서는 특정 SyntaxNode를 생성할 수 있는 Factory 메서드를 제공해 줍니다.

예를 들어, "using System.Collections.Generic" 선언을 위해 다음과 같은 작업들이 수반됩니다.

NameSyntax name = Syntax.IdentifierName("System");
name = Syntax.QualifiedName(left: name, right: Syntax.IdentifierName("Collections"));
name = Syntax.QualifiedName(left: name, right: Syntax.IdentifierName("Generic"));

Console.WriteLine(name.GetText());

// 출력 결과:
System.Collections.Generic

마치 기존의 Expression Tree를 사용한 것과 방식이 유사합니다. (프로그래밍 언어의 구문 분석이 그러하니 비슷하겠지요. ^^)

자, 이렇게 '새로운 SyntaxNode'를 하나 생성했으면 변경이 필요한 기존 SyntaxNode를 지정하고 교체를 해야겠지요. 이를 위해서 다음의 예제코드에서처럼 Update / Replace 메서드를 제공하고 있습니다.

SyntaxTree tree = SyntaxTree.ParseCompilationUnit(
    @"using System;
    using System.Collections;
    using System.Linq;
    using System.Text;
 
    namespace HelloWorld
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine(""Hello, World!"");
            }
        }
    }");

var root = (CompilationUnitSyntax)tree.Root;
var oldUsing = root.Usings[1];
var newUsing = oldUsing.Update(oldUsing.UsingKeyword,
                                oldUsing.AliasOpt,
                                name,
                                oldUsing.SemicolonToken);

var modifiedRoot = root.ReplaceNode(oldUsing, newUsing);

Console.WriteLine(modifiedRoot.GetText());

// 출력 결과:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello, World!");
        }
    }
}

아마도 예전 같았으면.... 간단하게 "using System.Collections;"을 문자열 검색으로 찾아서 "using System.Collections.Generic;"로 바꿨을 지도 모릅니다. 이제는 Roslyn이 나왔으니, C# 언어의 문법에 맞게 안정적으로 코드를 조작하는 것이 가능해 진 것입니다.




사실, 이런 유의 작업에서 대부분의 경우 공통적으로 SyntaxTree에 대해서 '탐색'하는 작업을 코드로 구현해야 할 텐데요. 물론, 사용자가 직접 만들어도 되지만 어찌 보면 이런 코드가 대체적으로 정형화된 패턴이기 때문에 마이크로소프트는 Rosyln에서 SyntaxRewriter 타입을 통해서 마치 XML의 SAX parser처럼 노드를 열람해 주는 기반을 제공해 주고 있습니다.

이 때문에, 개발자가 해주어야 하는 것은 단지 SyntaxRewriter를 상속받아서,

public class MyRewriter : SyntaxRewriter
{
}

원하는 '대체 노드' 후보자들이 열람되었을 때 알려주는 메서드를 override해서 구현 코드를 넣어주면 되는데, SyntaxRewriter는 다음과 같이 대부분의 구문 요소에 대해 override 함수들을 제공해 주고 있습니다.

protected internal override SyntaxNode VisitAccessorDeclaration(AccessorDeclarationSyntax node);
protected internal override SyntaxNode VisitAccessorList(AccessorListSyntax node);
protected internal override SyntaxNode VisitAliasQualifiedName(AliasQualifiedNameSyntax node);
protected internal override SyntaxNode VisitAnonymousMethodExpression(AnonymousMethodExpressionSyntax node);
protected internal override SyntaxNode VisitAnonymousObjectCreationExpression(AnonymousObjectCreationExpressionSyntax node);
protected internal override SyntaxNode VisitArgument(ArgumentSyntax node);
protected internal override SyntaxNode VisitArgumentList(ArgumentListSyntax node);
protected internal override SyntaxNode VisitArrayCreationExpression(ArrayCreationExpressionSyntax node);
protected internal override SyntaxNode VisitArrayRankSpecifier(ArrayRankSpecifierSyntax node);
protected internal override SyntaxNode VisitArrayType(ArrayTypeSyntax node);
protected internal override SyntaxNode VisitAttribute(AttributeSyntax node);
protected internal override SyntaxNode VisitAttributeArgument(AttributeArgumentSyntax node);
protected internal override SyntaxNode VisitAttributeArgumentList(AttributeArgumentListSyntax node);
protected internal override SyntaxNode VisitAttributeDeclaration(AttributeDeclarationSyntax node);
protected internal override SyntaxNode VisitAttributeTargetSpecifier(AttributeTargetSpecifierSyntax node);
protected internal override SyntaxNode VisitBadDirective(BadDirectiveSyntax node);
protected internal override SyntaxNode VisitBaseExpression(BaseExpressionSyntax node);
protected internal override SyntaxNode VisitBaseList(BaseListSyntax node);
protected internal override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax node);
protected internal override SyntaxNode VisitBlock(BlockSyntax node);
protected internal override SyntaxNode VisitBracketedArgumentList(BracketedArgumentListSyntax node);
protected internal override SyntaxNode VisitBracketedParameterList(BracketedParameterListSyntax node);
protected internal override SyntaxNode VisitBreakStatement(BreakStatementSyntax node);
protected internal override SyntaxNode VisitCastExpression(CastExpressionSyntax node);
protected internal override SyntaxNode VisitCatchClause(CatchClauseSyntax node);
protected internal override SyntaxNode VisitCatchDeclaration(CatchDeclarationSyntax node);
protected internal override SyntaxNode VisitCheckedExpression(CheckedExpressionSyntax node);
protected internal override SyntaxNode VisitCheckedStatement(CheckedStatementSyntax node);
protected internal override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node);
protected internal override SyntaxNode VisitClassOrStructConstraint(ClassOrStructConstraintSyntax node);
protected internal override SyntaxNode VisitCompilationUnit(CompilationUnitSyntax node);
protected internal override SyntaxNode VisitConditionalExpression(ConditionalExpressionSyntax node);
protected internal override SyntaxNode VisitConstructorConstraint(ConstructorConstraintSyntax node);
protected internal override SyntaxNode VisitConstructorDeclaration(ConstructorDeclarationSyntax node);
protected internal override SyntaxNode VisitConstructorInitializer(ConstructorInitializerSyntax node);
protected internal override SyntaxNode VisitContinueStatement(ContinueStatementSyntax node);
protected internal override SyntaxNode VisitConversionOperatorDeclaration(ConversionOperatorDeclarationSyntax node);
protected internal override SyntaxNode VisitDefaultExpression(DefaultExpressionSyntax node);
protected internal override SyntaxNode VisitDefineDirective(DefineDirectiveSyntax node);
protected internal override SyntaxNode VisitDelegateDeclaration(DelegateDeclarationSyntax node);
protected internal override SyntaxNode VisitDestructorDeclaration(DestructorDeclarationSyntax node);
protected internal override SyntaxNode VisitDocumentationComment(DocumentationCommentSyntax node);
protected internal override SyntaxNode VisitDoStatement(DoStatementSyntax node);
protected internal override SyntaxNode VisitElementAccessExpression(ElementAccessExpressionSyntax node);
protected internal override SyntaxNode VisitElifDirective(ElifDirectiveSyntax node);
protected internal override SyntaxNode VisitElseClause(ElseClauseSyntax node);
protected internal override SyntaxNode VisitElseDirective(ElseDirectiveSyntax node);
protected internal override SyntaxNode VisitEmptyStatement(EmptyStatementSyntax node);
protected internal override SyntaxNode VisitEndIfDirective(EndIfDirectiveSyntax node);
protected internal override SyntaxNode VisitEndRegionDirective(EndRegionDirectiveSyntax node);
protected internal override SyntaxNode VisitEnumDeclaration(EnumDeclarationSyntax node);
protected internal override SyntaxNode VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node);
protected internal override SyntaxNode VisitEqualsValueClause(EqualsValueClauseSyntax node);
protected internal override SyntaxNode VisitErrorDirective(ErrorDirectiveSyntax node);
protected internal override SyntaxNode VisitEventDeclaration(EventDeclarationSyntax node);
protected internal override SyntaxNode VisitEventFieldDeclaration(EventFieldDeclarationSyntax node);
protected internal override SyntaxNode VisitExplicitInterfaceSpecifier(ExplicitInterfaceSpecifierSyntax node);
protected internal override SyntaxNode VisitExpressionStatement(ExpressionStatementSyntax node);
protected internal override SyntaxNode VisitExternAliasDirective(ExternAliasDirectiveSyntax node);
protected internal override SyntaxNode VisitFieldDeclaration(FieldDeclarationSyntax node);
protected internal override SyntaxNode VisitFinallyClause(FinallyClauseSyntax node);
protected internal override SyntaxNode VisitFixedStatement(FixedStatementSyntax node);
protected internal override SyntaxNode VisitForEachStatement(ForEachStatementSyntax node);
protected internal override SyntaxNode VisitForStatement(ForStatementSyntax node);
protected internal override SyntaxNode VisitFromClause(FromClauseSyntax node);
protected internal override SyntaxNode VisitGenericName(GenericNameSyntax node);
protected internal override SyntaxNode VisitGlobalStatement(GlobalStatementSyntax node);
protected internal override SyntaxNode VisitGotoStatement(GotoStatementSyntax node);
protected internal override SyntaxNode VisitGroupClause(GroupClauseSyntax node);
protected internal override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node);
protected internal override SyntaxNode VisitIfDirective(IfDirectiveSyntax node);
protected internal override SyntaxNode VisitIfStatement(IfStatementSyntax node);
protected internal override SyntaxNode VisitImplicitArrayCreationExpression(ImplicitArrayCreationExpressionSyntax node);
protected internal override SyntaxNode VisitIncompleteMember(IncompleteMemberSyntax node);
protected internal override SyntaxNode VisitIndexerDeclaration(IndexerDeclarationSyntax node);
protected internal override SyntaxNode VisitInitializerExpression(InitializerExpressionSyntax node);
protected internal override SyntaxNode VisitInterfaceDeclaration(InterfaceDeclarationSyntax node);
protected internal override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax node);
protected internal override SyntaxNode VisitJoinClause(JoinClauseSyntax node);
protected internal override SyntaxNode VisitJoinIntoClause(JoinIntoClauseSyntax node);
protected internal override SyntaxNode VisitLabeledStatement(LabeledStatementSyntax node);
protected internal override SyntaxNode VisitLetClause(LetClauseSyntax node);
protected internal override SyntaxNode VisitLineDirective(LineDirectiveSyntax node);
protected internal override SyntaxNode VisitLiteralExpression(LiteralExpressionSyntax node);
protected internal override SyntaxNode VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node);
protected internal override SyntaxNode VisitLockStatement(LockStatementSyntax node);
protected internal override SyntaxNode VisitMakeRefExpression(MakeRefExpressionSyntax node);
protected internal override SyntaxNode VisitMemberAccessExpression(MemberAccessExpressionSyntax node);
protected internal override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node);
protected internal override SyntaxNode VisitNameColon(NameColonSyntax node);
protected internal override SyntaxNode VisitNameEquals(NameEqualsSyntax node);
protected internal override SyntaxNode VisitNamespaceDeclaration(NamespaceDeclarationSyntax node);
protected internal override SyntaxNode VisitNullableType(NullableTypeSyntax node);
protected internal override SyntaxNode VisitObjectCreationExpression(ObjectCreationExpressionSyntax node);
protected internal override SyntaxNode VisitOperatorDeclaration(OperatorDeclarationSyntax node);
protected internal override SyntaxNode VisitOrderByClause(OrderByClauseSyntax node);
protected internal override SyntaxNode VisitOrdering(OrderingSyntax node);
protected internal override SyntaxNode VisitParameter(ParameterSyntax node);
protected internal override SyntaxNode VisitParameterList(ParameterListSyntax node);
protected internal override SyntaxNode VisitParenthesizedExpression(ParenthesizedExpressionSyntax node);
protected internal override SyntaxNode VisitParenthesizedLambdaExpression(ParenthesizedLambdaExpressionSyntax node);
protected internal override SyntaxNode VisitPointerType(PointerTypeSyntax node);
protected internal override SyntaxNode VisitPostfixUnaryExpression(PostfixUnaryExpressionSyntax node);
protected internal override SyntaxNode VisitPragmaChecksumDirective(PragmaChecksumDirectiveSyntax node);
protected internal override SyntaxNode VisitPragmaWarningDirective(PragmaWarningDirectiveSyntax node);
protected internal override SyntaxNode VisitPredefinedType(PredefinedTypeSyntax node);
protected internal override SyntaxNode VisitPrefixUnaryExpression(PrefixUnaryExpressionSyntax node);
protected internal override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax node);
protected internal override SyntaxNode VisitQualifiedName(QualifiedNameSyntax node);
protected internal override SyntaxNode VisitQueryContinuation(QueryContinuationSyntax node);
protected internal override SyntaxNode VisitQueryExpression(QueryExpressionSyntax node);
protected internal override SyntaxNode VisitReferenceDirective(ReferenceDirectiveSyntax node);
protected internal override SyntaxNode VisitRefTypeExpression(RefTypeExpressionSyntax node);
protected internal override SyntaxNode VisitRefValueExpression(RefValueExpressionSyntax node);
protected internal override SyntaxNode VisitRegionDirective(RegionDirectiveSyntax node);
protected internal override SyntaxNode VisitReturnStatement(ReturnStatementSyntax node);
protected internal override SyntaxNode VisitSelectClause(SelectClauseSyntax node);
protected internal override SyntaxNode VisitSimpleLambdaExpression(SimpleLambdaExpressionSyntax node);
protected internal override SyntaxNode VisitSizeOfExpression(SizeOfExpressionSyntax node);
protected internal override SyntaxNode VisitSkippedTokens(SkippedTokensSyntax node);
protected internal override SyntaxNode VisitStackAllocArrayCreationExpression(StackAllocArrayCreationExpressionSyntax node);
protected internal override SyntaxNode VisitStructDeclaration(StructDeclarationSyntax node);
protected internal override SyntaxNode VisitSwitchLabel(SwitchLabelSyntax node);
protected internal override SyntaxNode VisitSwitchSection(SwitchSectionSyntax node);
protected internal override SyntaxNode VisitSwitchStatement(SwitchStatementSyntax node);
protected internal override SyntaxNode VisitThisExpression(ThisExpressionSyntax node);
protected internal override SyntaxNode VisitThrowStatement(ThrowStatementSyntax node);
protected internal override SyntaxNode VisitTryStatement(TryStatementSyntax node);
protected internal override SyntaxNode VisitTypeArgumentList(TypeArgumentListSyntax node);
protected internal override SyntaxNode VisitTypeConstraint(TypeConstraintSyntax node);
protected internal override SyntaxNode VisitTypeOfExpression(TypeOfExpressionSyntax node);
protected internal override SyntaxNode VisitTypeParameter(TypeParameterSyntax node);
protected internal override SyntaxNode VisitTypeParameterConstraintClause(TypeParameterConstraintClauseSyntax node);
protected internal override SyntaxNode VisitTypeParameterList(TypeParameterListSyntax node);
protected internal override SyntaxNode VisitUndefDirective(UndefDirectiveSyntax node);
protected internal override SyntaxNode VisitUnsafeStatement(UnsafeStatementSyntax node);
protected internal override SyntaxNode VisitUsingDirective(UsingDirectiveSyntax node);
protected internal override SyntaxNode VisitUsingStatement(UsingStatementSyntax node);
protected internal override SyntaxNode VisitVariableDeclaration(VariableDeclarationSyntax node);
protected internal override SyntaxNode VisitVariableDeclarator(VariableDeclaratorSyntax node);
protected internal override SyntaxNode VisitWarningDirective(WarningDirectiveSyntax node);
protected internal override SyntaxNode VisitWhereClause(WhereClauseSyntax node);
protected internal override SyntaxNode VisitWhileStatement(WhileStatementSyntax node);
protected internal override SyntaxNode VisitXmlAttribute(XmlAttributeSyntax node);
protected internal override SyntaxNode VisitXmlCDataSection(XmlCDataSectionSyntax node);
protected internal override SyntaxNode VisitXmlComment(XmlCommentSyntax node);
protected internal override SyntaxNode VisitXmlElement(XmlElementSyntax node);
protected internal override SyntaxNode VisitXmlElementEndTag(XmlElementEndTagSyntax node);
protected internal override SyntaxNode VisitXmlElementStartTag(XmlElementStartTagSyntax node);
protected internal override SyntaxNode VisitXmlEmptyElement(XmlEmptyElementSyntax node);
protected internal override SyntaxNode VisitXmlName(XmlNameSyntax node);
protected internal override SyntaxNode VisitXmlPrefix(XmlPrefixSyntax node);
protected internal override SyntaxNode VisitXmlProcessingInstruction(XmlProcessingInstructionSyntax node);
protected internal override SyntaxNode VisitXmlText(XmlTextSyntax node);
protected internal override SyntaxNode VisitYieldStatement(YieldStatementSyntax node);

"Getting Started - Syntax Transformation (CSharp)" 문서에 실린 예제에서는 로컬 변수 선언에 대해서 'var' 키워드로 바꾸는 것이 가능한 경우를 찾아서 해당 키워드로 대체해 주고 있기 때문에 VisitLocalDeclarationStatement 메서드를 재정의하고 있습니다.

public class TypeInferenceRewriter : SyntaxRewriter
{
    private readonly SemanticModel SemanticModel;
 
    public TypeInferenceRewriter(SemanticModel semanticModel)
    {
        this.SemanticModel = semanticModel;
    }
 
    protected override SyntaxNode VisitLocalDeclarationStatement(
                                        LocalDeclarationStatementSyntax node)
    {
        if (node.Declaration.Variables.Count > 1) 
        {
            return node;
        }
        if (node.Declaration.Variables[0].InitializerOpt == null)
        {
            return node;
        }
 
        VariableDeclaratorSyntax declarator = node.Declaration.Variables.First();                 
        TypeSyntax variableTypeName = node.Declaration.Type;
            
        TypeSymbol variableType = 
            SemanticModel.GetSemanticInfo(variableTypeName).Type;
            
        SemanticInfo initializerInfo = 
            SemanticModel.GetSemanticInfo(declarator.InitializerOpt.Value);
            
        if (variableType == initializerInfo.Type)
        {
            TypeSyntax varTypeName = 
                Syntax.IdentifierName("var")
                        .WithLeadingTrivia(variableTypeName.GetLeadingTrivia())
                        .WithTrailingTrivia(variableTypeName.GetTrailingTrivia());
 
            return node.ReplaceNode(variableTypeName, varTypeName);
        }
        else
        {
            return node;
        }
    }
}

C# 구문을 해석하는 것을 넘어서, 이제는 문법에 맞게 변경도 할 수 있게 되었군요. ^^




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 7/10/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2011-10-31 04시04분
"%PROGRAMFILES% (x86)\Microsoft Codename Roslyn CTP" 폴더에서 가장 중요한 "Roslyn Project Overview.docx" 파일의 번역본은 다음의 경로에서 제공되고 있습니다. ^^

The Roslyn Project 번역판
; (broken) http://blogs.msdn.com/b/heejaechang/archive/2011/10/23/the-roslyn-project.aspx
정성태
2021-04-23 11시50분
conan-roslyn/Conan (Archived 상태)
 - lightweight fork of the .NET Compiler Platform ("Roslyn") by adding a compiler plugin infrastructure.
; https://github.com/conan-roslyn/Conan
정성태

1  2  3  4  5  6  7  8  9  10  11  12  13  [14]  15  ...
NoWriterDateCnt.TitleFile(s)
13273정성태2/28/20233973.NET Framework: 2099. C# - 관리 포인터로서의 ref 예약어 의미
13272정성태2/27/20234234오류 유형: 850. SSMS - mdf 파일을 Attach 시킬 때 Operating system error 5: "5(Access is denied.)" 에러
13271정성태2/25/20234152오류 유형: 849. Sql Server Configuration Manager가 시작 메뉴에 없는 경우
13270정성태2/24/20233781.NET Framework: 2098. dotnet build에 /p 옵션을 적용 시 유의점
13269정성태2/23/20234312스크립트: 46. 파이썬 - uvicorn의 콘솔 출력을 UDP로 전송
13268정성태2/22/20234860개발 환경 구성: 667. WSL 2 내부에서 열고 있는 UDP 서버를 호스트 측에서 접속하는 방법
13267정성태2/21/20234779.NET Framework: 2097. C# - 비동기 소켓 사용 시 메모리 해제가 finalizer 단계에서 발생하는 사례파일 다운로드1
13266정성태2/20/20234398오류 유형: 848. .NET Core/5+ - Process terminated. Couldn't find a valid ICU package installed on the system
13265정성태2/18/20234306.NET Framework: 2096. .NET Core/5+ - PublishSingleFile 유형에 대한 runtimeconfig.json 설정
13264정성태2/17/20235804스크립트: 45. 파이썬 - uvicorn 사용자 정의 Logger 작성
13263정성태2/16/20233960개발 환경 구성: 666. 최신 버전의 ilasm.exe/ildasm.exe 사용하는 방법
13262정성태2/15/20235034디버깅 기술: 191. dnSpy를 이용한 (소스 코드가 없는) 닷넷 응용 프로그램 디버깅 방법 [1]
13261정성태2/15/20234306Windows: 224. Visual Studio - 영문 폰트가 Fullwidth Latin Character로 바뀌는 문제
13260정성태2/14/20234104오류 유형: 847. ilasm.exe 컴파일 오류 - error : syntax error at token '-' in ... -inf
13259정성태2/14/20234223.NET Framework: 2095. C# - .NET5부터 도입된 CollectionsMarshal
13258정성태2/13/20234121오류 유형: 846. .NET Framework 4.8 Developer Pack 설치 실패 - 0x81f40001
13257정성태2/13/20234206.NET Framework: 2094. C# - Job에 Process 포함하는 방법 [1]파일 다운로드1
13256정성태2/10/20235058개발 환경 구성: 665. WSL 2의 네트워크 통신 방법 - 두 번째 이야기
13255정성태2/10/20234355오류 유형: 845. gihub - windows2022 이미지에서 .NET Framework 4.5.2 미만의 프로젝트에 대한 빌드 오류
13254정성태2/10/20234266Windows: 223. (WMI 쿼리를 위한) PowerShell 문자열 escape 처리
13253정성태2/9/20235045Windows: 222. C# - 다른 윈도우 프로그램이 실행되었음을 인식하는 방법파일 다운로드1
13252정성태2/9/20233856오류 유형: 844. ssh로 명령어 수행 시 멈춤 현상
13251정성태2/8/20234321스크립트: 44. 파이썬의 3가지 스레드 ID
13250정성태2/8/20236121오류 유형: 843. System.InvalidOperationException - Unable to configure HTTPS endpoint
13249정성태2/7/20234934오류 유형: 842. 리눅스 - You must wait longer to change your password
13248정성태2/7/20234050오류 유형: 841. 리눅스 - [사용자 계정] is not in the sudoers file. This incident will be reported.
1  2  3  4  5  6  7  8  9  10  11  12  13  [14]  15  ...