Microsoft MVP성태의 닷넷 이야기
.NET Framework: 258. Roslyn 맛보기 - SyntaxTree 조작 [링크 복사], [링크+제목 복사],
조회: 27601
글쓴 사람
정성태 (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
정성태

... 106  107  108  109  110  111  112  113  114  115  116  117  [118]  119  120  ...
NoWriterDateCnt.TitleFile(s)
11007정성태8/1/201624792오류 유형: 344. RDP ActiveX 컨트롤로 특정 PC에 연결할 수 없을 때, 오류 상황을 해결하기 위한 팁파일 다운로드1
11006정성태7/22/201627996개발 환경 구성: 288. SSL 인증서를 Azure Cloud Service에 적용하는 방법
11005정성태7/22/201626668개발 환경 구성: 287. Let's Encrypt 인증서 업데이트 주기: 90일
11004정성태7/22/201621424오류 유형: 343. Invalid service definition or service configuration. Please see the Error List for more details.
11003정성태7/20/201628809VS.NET IDE: 110. Visual Studio 2015에서 .NET Core 응용 프로그램 개발 [1]
11002정성태7/20/201622120개발 환경 구성: 286. Microsoft Azure 서비스의 구독은 반드시 IE로!
11001정성태7/19/201633195.NET Framework: 599. .NET Core/SDK 설치 및 기본 사용법 [6]
11000정성태7/16/201621922오류 유형: 342. Microsoft Visual Studio 2010 Tools for Office Runtime (x86 and x64) 설치 시 오류
10999정성태7/16/201622853오류 유형: 341. .NET Framework 4.5.2가 설치 안 되는 경우
10998정성태7/16/201622593.NET Framework: 598. C# - Excel 시트에 윈도우 폼 기능을 추가하는 방법 [1]파일 다운로드1
10997정성태7/16/201622774오류 유형: 340. HTTP Error 500.23 - Internal Server Error파일 다운로드1
10996정성태7/14/201628078Windows: 118. 유선 접속 상태에서 재부팅하면 무선 연결이 자동 연결 안되는 문제 [4]파일 다운로드1
10995정성태6/27/201621598VS.NET IDE: 109. Visual Studio 유료 버전 사용자의 주기적인 온라인 인증을 없애는 방법
10994정성태6/23/201620961개발 환경 구성: 285. 알고스팟(https://algospot.com)을 위한 Visual C++ 답안 작성 요령파일 다운로드1
10993정성태6/23/201622078.NET Framework: 597. 닷넷 메타데이터에 struct/class(값/참조 형식)의 구분이 있을까요?
10992정성태6/13/201618788오류 유형: 339. vbs 스크립트 실행 시 항상 실행 여부를 묻는 질문 창이 뜬다면?
10991정성태6/13/201623879오류 유형: 338. octave-gui 실행 시 "octave-gui.exe has stopped working" 오류
10990정성태6/13/201625356오류 유형: 337. missing type specifier - [type] assumed. Note: C++ does not support default-[type]
10989정성태6/7/201621835.NET Framework: 596. C# - WCF wsDualHttpBinding의 ClientBaseAddress 속성 - 두 번째 이야기
10988정성태6/3/201622939기타: 57. Outlook blocked access to the following potentially unsafe attachments
10987정성태6/2/201623965.NET Framework: 595. XLL 파일에 포함된 .NET 어셈블리를 추출하는 방법
10986정성태6/1/201624384.NET Framework: 594. C# - WCF wsDualHttpBinding의 ClientBaseAddress 속성
10985정성태6/1/201622887오류 유형: 336. An error occurred while ejecting 'DVD RW drive ...'
10984정성태5/31/201628578.NET Framework: 593. C# - wsDualHttpBinding WCF 예제 프로그램파일 다운로드1
10983정성태5/30/201622543VC++: 97. C++ 템플릿 remove_pointer, enable_if, is_pointer 사용 예제파일 다운로드1
10982정성태5/26/201620832오류 유형: 335. SQL Server Management Studio - The database ... is not accessible.
... 106  107  108  109  110  111  112  113  114  115  116  117  [118]  119  120  ...