Microsoft MVP성태의 닷넷 이야기
.NET Framework: 258. Roslyn 맛보기 - SyntaxTree 조작 [링크 복사], [링크+제목 복사]
조회: 18962
글쓴 사람
정성태 (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)
13560정성태2/19/20242054디버깅 기술: 195. windbg 분석 사례 - Semaphore 잠금으로 인한 Hang 현상 (닷넷)
13559정성태2/19/20242937오류 유형: 895. ASP.NET - System.Security.SecurityException: 'Requested registry access is not allowed.'
13558정성태2/18/20242160닷넷: 2217. C# - 최댓값이 1인 SemaphoreSlim 보다 Mutex 또는 lock(obj)를 선택하는 것이 나은 이유
13557정성태2/18/20241913Windows: 258. Task Scheduler의 Author 속성 값을 변경하는 방법
13556정성태2/17/20241956Windows: 257. Windows - Symbolic (hard/soft) Link 및 Junction 차이점
13555정성태2/15/20242112닷넷: 2216. C# - SemaphoreSlim 사용 시 주의점
13554정성태2/15/20241856VS.NET IDE: 189. Visual Studio - 닷넷 소스코드 디컴파일 찾기가 안 될 때
13553정성태2/14/20241938닷넷: 2215. windbg - thin/fat lock 없이 동작하는 Monitor.Wait + Pulse
13552정성태2/13/20241887닷넷: 2214. windbg - Monitor.Enter의 thin lock과 fat lock
13551정성태2/12/20242084닷넷: 2213. ASP.NET/Core 웹 응용 프로그램 - 2차 스레드의 예외로 인한 비정상 종료
13550정성태2/11/20242198Windows: 256. C# - Server socket이 닫히면 Accept 시켰던 자식 소켓이 닫힐까요?
13549정성태2/3/20242500개발 환경 구성: 706. C# - 컨테이너에서 실행하기 위한 (소켓) 콘솔 프로젝트 구성
13548정성태2/1/20242330개발 환경 구성: 705. "Docker Desktop for Windows" - ASP.NET Core 응용 프로그램의 소켓 주소 바인딩(IPv4/IPv6 loopback, Any)
13547정성태1/31/20242084개발 환경 구성: 704. Visual Studio - .NET 8 프로젝트부터 dockerfile에 추가된 "USER app" 설정
13546정성태1/30/20241940Windows: 255. (디버거의 영향 등으로) 대상 프로세스가 멈추면 Socket KeepAlive로 연결이 끊길까요?
13545정성태1/30/20241858닷넷: 2212. ASP.NET Core - 우선순위에 따른 HTTP/HTTPS 호스트:포트 바인딩 방법
13544정성태1/30/20241882오류 유형: 894. Microsoft.Data.SqlClient - Could not load file or assembly 'System.Security.Permissions, ...'
13543정성태1/30/20241880Windows: 254. Windows - 기본 사용 중인 5357 포트 비활성화는 방법
13542정성태1/30/20241912오류 유형: 893. Visual Studio - Web Application을 실행하지 못하는 IISExpress - 두 번째 이야기
13541정성태1/29/20241954VS.NET IDE: 188. launchSettings.json의 useSSL 옵션
13540정성태1/29/20242075Linux: 69. 리눅스 - "Docker Desktop for Windows" Container 환경에서 IPv6 Loopback Address 바인딩 오류
13539정성태1/26/20242363개발 환경 구성: 703. Visual Studio - launchSettings.json을 이용한 HTTP/HTTPS 포트 바인딩
13538정성태1/25/20242414닷넷: 2211. C# - NonGC(FOH) 영역에 .NET 개체를 생성파일 다운로드1
13537정성태1/24/20242497닷넷: 2210. C# - Native 메모리에 .NET 개체를 생성파일 다운로드1
13536정성태1/23/20242585닷넷: 2209. .NET 8 - NonGC Heap / FOH (Frozen Object Heap) [1]
13535정성태1/22/20242429닷넷: 2208. C# - GCHandle 구조체의 메모리 분석
1  2  [3]  4  5  6  7  8  9  10  11  12  13  14  15  ...