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

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# 구문을 해석하는 것을 넘어서, 이제는 문법에 맞게 변경도 할 수 있게 되었군요. ^^




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

[연관 글]


donaricano-btn



[최초 등록일: ]
[최종 수정일: 4/23/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)
12645정성태5/14/202115사물인터넷: 64. NodeMCU v1 ESP8266 - LittleFS를 이용한 와이파이 접속 정보 업데이트파일 다운로드1
12644정성태5/14/20212오류 유형: 719. 윈도우 - 제어판의 "프로그램 및 기능" / "Windows 기능 켜기/끄기" 오류 0x800736B3
12643정성태5/14/20212오류 유형: 718. 서버 유형의 COM+ 사용 시 0x80080005(Server execution failed) 오류 발생
12642정성태5/14/20213오류 유형: 717. The 'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine.
12641정성태5/13/202143디버깅 기술: 179. 윈도우 용 .NET Core 3 이상에서 Windbg의 sos 사용법
12640정성태5/13/202119오류 유형: 716. RDP 연결 - Because of a protocol error (code: 0x112f), the remote session will be disconnected.
12639정성태5/12/202115오류 유형: 715. Arduino: Open Serial Monitor - The module '...\detection.node' was compiled against a different Node.js version using NODE_MODULE_VERSION
12638정성태5/12/202136사물인터넷: 63. NodeMCU v1 ESP8266 - 펌웨어 내 파일 시스템(SPIFFS, LittleFS) 및 EEPROM 활용
12637정성태5/10/202140사물인터넷: 62. NodeMCU v1 ESP8266 보드의 A0 핀에 다중 아날로그 센서 연결
12636정성태5/10/202147사물인터넷: 61. NodeMCU v1 ESP8266 보드의 A0 핀 사용법 - FSR-402 아날로그 압력 센서 연동파일 다운로드1
12635정성태5/9/202160기타: 81. OpenTabletDriver를 (관리자 권한으로 실행하지 않고도) 관리자 권한의 프로그램에서 동작하게 만드는 방법
12634정성태5/9/202162개발 환경 구성: 572. .NET에서의 신뢰도 등급 조정 - 외부 Manifest 파일을 두는 방법파일 다운로드1
12633정성태5/7/202193개발 환경 구성: 571. UAC - 관리자 권한 없이 UIPI 제약을 없애는 방법
12632정성태5/8/202199기타: 80. (WACOM도 지원하는) Tablet 공통 디바이스 드라이버 - OpenTabletDriver
12631정성태5/7/2021107사물인터넷: 60. ThingSpeak 사물인터넷 플랫폼에 ESP8266 NodeMCU v1 + 조도 센서 장비 연동파일 다운로드1
12630정성태5/12/202179사물인터넷: 59. NodeMCU v1 ESP8266 보드의 A0 핀 사용법 - CdS Cell(GL3526) 조도 센서 연동파일 다운로드1
12629정성태5/5/2021167.NET Framework: 1057. C# - CoAP 서버 및 클라이언트 제작 (UDP 소켓 통신)파일 다운로드1
12628정성태5/4/202146Linux: 39. Eclipse 원격 디버깅 - Cannot run program "gdb": Launching failed
12627정성태5/4/202155Linux: 38. 라즈베리 파이 제로 용 프로그램 개발을 위한 Eclipse C/C++ 윈도우 환경 설정
12626정성태5/14/202173.NET Framework: 1056. C# - Thread.Suspend 호출 시 응용 프로그램 hang 현상 (2)파일 다운로드1
12625정성태5/3/202142오류 유형: 714. error CS5001: Program does not contain a static 'Main' method suitable for an entry point
12624정성태5/3/2021264.NET Framework: 1055. C# - struct/class가 스택/힙에 할당되는 사례 정리 [6]파일 다운로드1
12623정성태5/2/2021130.NET Framework: 1054. C# 9 최상위 문에 STAThread 사용파일 다운로드1
12622정성태5/3/202146오류 유형: 713. XSD 파일을 포함한 프로젝트 - The type or namespace name 'TypedTableBase<>' does not exist in the namespace 'System.Data'
12621정성태5/1/2021158.NET Framework: 1053. C# - 특정 레지스트리 변경 시 알림을 받는 방법파일 다운로드1
[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...