Share via


DirectiveProcessor 类

具体指令处理器的抽象基类。

继承层次结构

System.Object
  Microsoft.VisualStudio.TextTemplating.DirectiveProcessor
    Microsoft.VisualStudio.TextTemplating.ParameterDirectiveProcessor
    Microsoft.VisualStudio.TextTemplating.RequiresProvidesDirectiveProcessor

命名空间:  Microsoft.VisualStudio.TextTemplating
程序集:  Microsoft.VisualStudio.TextTemplating.11.0(在 Microsoft.VisualStudio.TextTemplating.11.0.dll 中)

语法

声明
Public MustInherit Class DirectiveProcessor _
    Implements IDirectiveProcessor
public abstract class DirectiveProcessor : IDirectiveProcessor
public ref class DirectiveProcessor abstract : IDirectiveProcessor
[<AbstractClass>]
type DirectiveProcessor =  
    class
        interface IDirectiveProcessor
    end
public abstract class DirectiveProcessor implements IDirectiveProcessor

DirectiveProcessor 类型公开以下成员。

构造函数

  名称 说明
受保护的方法 DirectiveProcessor 在派生类中重写时,初始化 DirectiveProcessor 类的新实例。

页首

属性

  名称 说明
受保护的属性 Errors 让生成,在处理指令时的错误。

页首

方法

  名称 说明
公共方法 Equals 确定指定的对象是否等于当前对象。 (继承自 Object。)
受保护的方法 Finalize 允许对象在“垃圾回收”回收之前尝试释放资源并执行其他清理操作。 (继承自 Object。)
公共方法 FinishProcessingRun 在派生类中重写时,完成一轮指令处理。
公共方法 GetClassCodeForProcessingRun 在派生类中重写时,获取要添加到已生成转换类的代码。
公共方法 GetHashCode 用作特定类型的哈希函数。 (继承自 Object。)
公共方法 GetImportsForProcessingRun 在派生类中重写时,获取要导入到已生成转换类的命名空间。
公共方法 GetPostInitializationCodeForProcessingRun 在派生类中重写时,获取要添加到已生成转换类的 initialize 方法末尾的代码。
公共方法 GetPreInitializationCodeForProcessingRun 当重写在派生类中,获取代码添加到生成转换选件类的初始化方法的开头。
公共方法 GetReferencesForProcessingRun 在派生类中重写时,获取要传递到已生成转换类编译器的引用。
公共方法 GetTemplateClassCustomAttributes 获取将模板选件类的任何自定义属性。
公共方法 GetType 获取当前实例的 Type。 (继承自 Object。)
公共方法 Initialize 在派生类中重写时,初始化处理器实例。
公共方法 IsDirectiveSupported 当重写在派生类中,确定指令处理器是否支持指定的指令。
受保护的方法 MemberwiseClone 创建当前 Object 的浅表副本。 (继承自 Object。)
公共方法 ProcessDirective 在派生类中重写时,根据模板文件处理单个指令。
公共方法 StartProcessingRun 当重写在派生类中,开始舍入指令处理。
公共方法 ToString 返回表示当前对象的字符串。 (继承自 Object。)

页首

显式接口实现

  名称 说明
显式接口实现私有属性 IDirectiveProcessor.Errors
显式接口实现私有属性 IDirectiveProcessor.RequiresProcessingRunIsHostSpecific
显式接口实现私有方法 IDirectiveProcessor.SetProcessingRunIsHostSpecific

页首

备注

文本模板转换过程有两个步骤。 在第一步中,文本模板转换引擎将创建一个称为生成的转换类的类。 在第二步中,该引擎编译和执行生成的转换类,以产生生成的文本输出。

指令处理器通过向生成转换类添加代码发挥作用。 从文本模板调用指令,在调用一个指令后,文本模板中编写的其余代码可能依赖该指令提供的功能。 您可以编写自己的自定义指令处理器来提供文本模板的自定义功能。

有关更多信息,请参见 创建自定义 T4 文本模板指令处理器

文本模板转换引擎将保留任何所需的 DirectiveProcessor 类的单一实例。

DirectiveProcessor 实现状态机。

例如,如果文本模板具有同一指令处理器的三个指令调用,则引擎将会按以下顺序调用以下方法:

示例

下面的示例创建一个自定义指令处理器。 自定义指令处理器包含读取 XML 文件的一个指令。 该指令在 XmlDocument 变量中存储 XML,通过属性公开 XmlDocument

有关更多信息,请参见演练:创建自定义指令处理器

using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using Microsoft.VisualStudio.TextTemplating;

namespace CustomDP
{
    public class CustomDirectiveProcessor : DirectiveProcessor
    {
        //this buffer stores the code that is added to the 
        //generated transformation class after all the processing is done 
        //---------------------------------------------------------------------
        private StringBuilder codeBuffer;


        //Using a Code Dom Provider creates code for the 
        //generated transformation class in either Visual Basic or C#.
        //If you want your directive processor to support only one language, you
        //can hard code the code you add to the generated transformation class.
        //In that case, you do not need this field.
        //--------------------------------------------------------------------------
        private CodeDomProvider codeDomProvider;


        //this stores the full contents of the text template that is being processed
        //--------------------------------------------------------------------------
        private String templateContents;


        //These are the errors that occur during processing. The engine passes 
        //the errors to the host, and the host can decide how to display them,
        //for example the the host can display the errors in the UI
        //or write them to a file.
        //---------------------------------------------------------------------
        private CompilerErrorCollection errorsValue;
        public new CompilerErrorCollection Errors
        {
            get { return errorsValue; }
        }


        //Each time this directive processor is called, it creates a new property.
        //We count how many times we are called, and append "n" to each new
        //property name. The property names are therefore unique.
        //-----------------------------------------------------------------------------
        private int directiveCount = 0;


        public override void Initialize(ITextTemplatingEngineHost host)
        {
            //we do not need to do any initialization work
        }


        public override void StartProcessingRun(CodeDomProvider languageProvider, String templateContents, CompilerErrorCollection errors)
        {
            //the engine has passed us the language of the text template
            //we will use that language to generate code later
            //----------------------------------------------------------
            this.codeDomProvider = languageProvider;
            this.templateContents = templateContents;
            this.errorsValue = errors;

            this.codeBuffer = new StringBuilder();
        }


        //Before calling the ProcessDirective method for a directive, the 
        //engine calls this function to see whether the directive is supported.
        //Notice that one directive processor might support many directives.
        //---------------------------------------------------------------------
        public override bool IsDirectiveSupported(string directiveName)
        {
            if (string.Compare(directiveName, "CoolDirective", StringComparison.OrdinalIgnoreCase) == 0)
            {
                return true;
            }
            if (string.Compare(directiveName, "SuperCoolDirective", StringComparison.OrdinalIgnoreCase) == 0)
            {
                return true;
            }
            return false;
        }


        public override void ProcessDirective(string directiveName, IDictionary<string, string> arguments)
        {
            if (string.Compare(directiveName, "CoolDirective", StringComparison.OrdinalIgnoreCase) == 0)
            {
                string fileName;

                if (!arguments.TryGetValue("FileName", out fileName))
                {
                    throw new DirectiveProcessorException("Required argument 'FileName' not specified.");
                }

                if (string.IsNullOrEmpty(fileName))
                {
                    throw new DirectiveProcessorException("Argument 'FileName' is null or empty.");
                }

                //Now we add code to the generated transformation class.
                //This directive supports either Visual Basic or C#, so we must use the
                //System.CodeDom to create the code.
                //If a directive supports only one language, you can hard code the code.
                //--------------------------------------------------------------------------

                CodeMemberField documentField = new CodeMemberField();

                documentField.Name = "document" + directiveCount + "Value";
                documentField.Type = new CodeTypeReference(typeof(XmlDocument));
                documentField.Attributes = MemberAttributes.Private;

                CodeMemberProperty documentProperty = new CodeMemberProperty();

                documentProperty.Name = "Document" + directiveCount;
                documentProperty.Type = new CodeTypeReference(typeof(XmlDocument));
                documentProperty.Attributes = MemberAttributes.Public;
                documentProperty.HasSet = false;
                documentProperty.HasGet = true;

                CodeExpression fieldName = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), documentField.Name);
                CodeExpression booleanTest = new CodeBinaryOperatorExpression(fieldName, CodeBinaryOperatorType.IdentityEquality, new CodePrimitiveExpression(null));
                CodeExpression rightSide = new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("XmlReaderHelper"), "ReadXml", new CodePrimitiveExpression(fileName));
                CodeStatement[] thenSteps = new CodeStatement[] { new CodeAssignStatement(fieldName, rightSide) };

                CodeConditionStatement ifThen = new CodeConditionStatement(booleanTest, thenSteps);
                documentProperty.GetStatements.Add(ifThen);

                CodeStatement s = new CodeMethodReturnStatement(fieldName);
                documentProperty.GetStatements.Add(s);

                CodeGeneratorOptions options = new CodeGeneratorOptions();
                options.BlankLinesBetweenMembers = true;
                options.IndentString = "    ";
                options.VerbatimOrder = true;
                options.BracingStyle = "C";

                using (StringWriter writer = new StringWriter(codeBuffer, CultureInfo.InvariantCulture))
                {
                    codeDomProvider.GenerateCodeFromMember(documentField, writer, options);
                    codeDomProvider.GenerateCodeFromMember(documentProperty, writer, options);
                }

            }//end CoolDirective


            //One directive processor can contain many directives.
            //If you want to support more directives, the code goes here...
            //-----------------------------------------------------------------
            if (string.Compare(directiveName, "supercooldirective", StringComparison.OrdinalIgnoreCase) == 0)
            {
                //code for SuperCoolDirective goes here...
            }//end SuperCoolDirective


            //Track how many times the processor has been called.
            //-----------------------------------------------------------------
            directiveCount++;

        }//end ProcessDirective


        public override void FinishProcessingRun()
        {
            this.codeDomProvider = null;

            //important: do not do this:
            //the get methods below are called after this method 
            //and the get methods can access this field
            //-----------------------------------------------------------------
            //this.codeBuffer = null;
        }


        public override string GetPreInitializationCodeForProcessingRun()
        {
            //Use this method to add code to the start of the 
            //Initialize() method of the generated transformation class.
            //We do not need any pre-initialization, so we will just return "".
            //-----------------------------------------------------------------
            //GetPreInitializationCodeForProcessingRun runs before the 
            //Initialize() method of the base class.
            //-----------------------------------------------------------------
            return String.Empty;
        }


        public override string GetPostInitializationCodeForProcessingRun()
        {
            //Use this method to add code to the end of the 
            //Initialize() method of the generated transformation class.
            //We do not need any post-initialization, so we will just return "".
            //------------------------------------------------------------------
            //GetPostInitializationCodeForProcessingRun runs after the
            //Initialize() method of the base class.
            //-----------------------------------------------------------------
            return String.Empty;
        }


        public override string GetClassCodeForProcessingRun()
        {
            //Return the code to add to the generated transformation class.
            //-----------------------------------------------------------------
            return codeBuffer.ToString();
        }


        public override string[] GetReferencesForProcessingRun()
        {
            //This returns the references that we want to use when 
            //compiling the generated transformation class.
            //-----------------------------------------------------------------
            //We need a reference to this assembly to be able to call 
            //XmlReaderHelper.ReadXml from the generated transformation class.
            //-----------------------------------------------------------------
            return new string[]
            {
                "System.Xml",
                this.GetType().Assembly.Location
            };
        }


        public override string[] GetImportsForProcessingRun()
        {
            //This returns the imports or using statements that we want to 
            //add to the generated transformation class.
            //-----------------------------------------------------------------
            //We need CustomDP to be able to call XmlReaderHelper.ReadXml
            //from the generated transformation class.
            //-----------------------------------------------------------------
            return new string[]
            {
                "System.Xml",
                "CustomDP"
            };
        }
    }//end class CustomDirectiveProcessor


    //-------------------------------------------------------------------------
    // the code that we are adding to the generated transformation class 
    // will call this method
    //-------------------------------------------------------------------------
    public static class XmlReaderHelper
    {
        public static XmlDocument ReadXml(string fileName)
        {
            XmlDocument d = new XmlDocument();

            using (XmlTextReader reader = new XmlTextReader(fileName))
            {
                try
                {
                    d.Load(reader);
                }
                catch (System.Xml.XmlException e)
                {
                    throw new DirectiveProcessorException("Unable to read the XML file.", e);
                }
            }
            return d;
        }
    }//end class XmlReaderHelper
}//end namespace CustomDP
Imports System
Imports System.CodeDom
Imports System.CodeDom.Compiler
Imports System.Collections.Generic
Imports System.Globalization
Imports System.IO
Imports System.Text
Imports System.Xml
Imports System.Xml.Serialization
Imports Microsoft.VisualStudio.TextTemplating

Namespace CustomDP

    Public Class CustomDirectiveProcessor
    Inherits DirectiveProcessor

        'this buffer stores the code that is added to the 
        'generated transformation class after all the processing is done 
        '---------------------------------------------------------------
        Private codeBuffer As StringBuilder


        'Using a Code Dom Provider creates code for the
        'generated transformation class in either Visual Basic or C#.
        'If you want your directive processor to support only one language, you
        'can hard code the code you add to the generated transformation class.
        'In that case, you do not need this field.
        '--------------------------------------------------------------------------
        Private codeDomProvider As CodeDomProvider


        'this stores the full contents of the text template that is being processed
        '--------------------------------------------------------------------------
        Private templateContents As String


        'These are the errors that occur during processing. The engine passes 
        'the errors to the host, and the host can decide how to display them,
        'for example the the host can display the errors in the UI
        'or write them to a file.
        '---------------------------------------------------------------------
        Private errorsValue As CompilerErrorCollection
        Public Shadows ReadOnly Property Errors() As CompilerErrorCollection
            Get
                Return errorsValue
            End Get
        End Property


        'Each time this directive processor is called, it creates a new property.
        'We count how many times we are called, and append "n" to each new
        'property name. The property names are therefore unique.
        '--------------------------------------------------------------------------
        Private directiveCount As Integer = 0


        Public Overrides Sub Initialize(ByVal host As ITextTemplatingEngineHost)

            'we do not need to do any initialization work
        End Sub


        Public Overrides Sub StartProcessingRun(ByVal languageProvider As CodeDomProvider, ByVal templateContents As String, ByVal errors As CompilerErrorCollection)

            'the engine has passed us the language of the text template
            'we will use that language to generate code later
            '----------------------------------------------------------
            Me.codeDomProvider = languageProvider
            Me.templateContents = templateContents
            Me.errorsValue = errors

            Me.codeBuffer = New StringBuilder()
        End Sub


        'Before calling the ProcessDirective method for a directive, the 
        'engine calls this function to see whether the directive is supported.
        'Notice that one directive processor might support many directives.
        '---------------------------------------------------------------------
        Public Overrides Function IsDirectiveSupported(ByVal directiveName As String) As Boolean

            If String.Compare(directiveName, "CoolDirective", StringComparison.OrdinalIgnoreCase) = 0 Then
                Return True
            End If

            If String.Compare(directiveName, "SuperCoolDirective", StringComparison.OrdinalIgnoreCase) = 0 Then
                Return True
            End If

            Return False
        End Function


        Public Overrides Sub ProcessDirective(ByVal directiveName As String, ByVal arguments As IDictionary(Of String, String))

            If String.Compare(directiveName, "CoolDirective", StringComparison.OrdinalIgnoreCase) = 0 Then

                Dim fileName As String

                If Not (arguments.TryGetValue("FileName", fileName)) Then
                    Throw New DirectiveProcessorException("Required argument 'FileName' not specified.")
                End If

                If String.IsNullOrEmpty(fileName) Then
                    Throw New DirectiveProcessorException("Argument 'FileName' is null or empty.")
                End If

                'Now we add code to the generated transformation class.
                'This directive supports either Visual Basic or C#, so we must use the
                'System.CodeDom to create the code.
                'If a directive supports only one language, you can hard code the code.
                '--------------------------------------------------------------------------

                Dim documentField As CodeMemberField = New CodeMemberField()

                documentField.Name = "document" & directiveCount & "Value"
                documentField.Type = New CodeTypeReference(GetType(XmlDocument))
                documentField.Attributes = MemberAttributes.Private

                Dim documentProperty As CodeMemberProperty = New CodeMemberProperty()

                documentProperty.Name = "Document" & directiveCount
                documentProperty.Type = New CodeTypeReference(GetType(XmlDocument))
                documentProperty.Attributes = MemberAttributes.Public
                documentProperty.HasSet = False
                documentProperty.HasGet = True

                Dim fieldName As CodeExpression = New CodeFieldReferenceExpression(New CodeThisReferenceExpression(), documentField.Name)
                Dim booleanTest As CodeExpression = New CodeBinaryOperatorExpression(fieldName, CodeBinaryOperatorType.IdentityEquality, New CodePrimitiveExpression(Nothing))
                Dim rightSide As CodeExpression = New CodeMethodInvokeExpression(New CodeTypeReferenceExpression("XmlReaderHelper"), "ReadXml", New CodePrimitiveExpression(fileName))
                Dim thenSteps As CodeStatement() = New CodeStatement() {New CodeAssignStatement(fieldName, rightSide)}

                Dim ifThen As CodeConditionStatement = New CodeConditionStatement(booleanTest, thenSteps)
                documentProperty.GetStatements.Add(ifThen)

                Dim s As CodeStatement = New CodeMethodReturnStatement(fieldName)
                documentProperty.GetStatements.Add(s)

                Dim options As CodeGeneratorOptions = New CodeGeneratorOptions()
                options.BlankLinesBetweenMembers = True
                options.IndentString = "    "
                options.VerbatimOrder = True
                options.BracingStyle = "VB"

                Using writer As StringWriter = New StringWriter(codeBuffer, CultureInfo.InvariantCulture)

                    codeDomProvider.GenerateCodeFromMember(documentField, writer, options)
                    codeDomProvider.GenerateCodeFromMember(documentProperty, writer, options)
                End Using

            End If  'CoolDirective


            'One directive processor can contain many directives.
            'If you want to support more directives, the code goes here...
            '-----------------------------------------------------------------
            If String.Compare(directiveName, "supercooldirective", StringComparison.OrdinalIgnoreCase) = 0 Then

                'code for SuperCoolDirective goes here
            End If 'SuperCoolDirective

            'Track how many times the processor has been called.
            '-----------------------------------------------------------------
            directiveCount += 1
        End Sub 'ProcessDirective


        Public Overrides Sub FinishProcessingRun()

            Me.codeDomProvider = Nothing

            'important: do not do this:
            'the get methods below are called after this method 
            'and the get methods can access this field
            '-----------------------------------------------------------------
            'Me.codeBuffer = Nothing
        End Sub


        Public Overrides Function GetPreInitializationCodeForProcessingRun() As String

            'Use this method to add code to the start of the 
            'Initialize() method of the generated transformation class.
            'We do not need any pre-initialization, so we will just return "".
            '-----------------------------------------------------------------
            'GetPreInitializationCodeForProcessingRun runs before the 
            'Initialize() method of the base class.
            '-----------------------------------------------------------------
            Return String.Empty
        End Function


        Public Overrides Function GetPostInitializationCodeForProcessingRun() As String

            'Use this method to add code to the end of the 
            'Initialize() method of the generated transformation class.
            'We do not need any post-initialization, so we will just return "".
            '------------------------------------------------------------------
            'GetPostInitializationCodeForProcessingRun runs after the
            'Initialize() method of the base class.
            '-----------------------------------------------------------------
            Return String.Empty
        End Function


        Public Overrides Function GetClassCodeForProcessingRun() As String

            'Return the code to add to the generated transformation class.
            '-----------------------------------------------------------------
            Return codeBuffer.ToString()
        End Function


        Public Overrides Function GetReferencesForProcessingRun() As String()

            'This returns the references that we want to use when 
            'compiling the generated transformation class.
            '-----------------------------------------------------------------
            'We need a reference to this assembly to be able to call 
            'XmlReaderHelper.ReadXml from the generated transformation class.
            '-----------------------------------------------------------------
            Return New String() {"System.Xml", Me.GetType().Assembly.Location}
        End Function


        Public Overrides Function GetImportsForProcessingRun() As String()

            'This returns the imports or using statements that we want to 
            'add to the generated transformation class.
            '-----------------------------------------------------------------
            'We need CustomDP to be able to call XmlReaderHelper.ReadXml
            'from the generated transformation class.
            '-----------------------------------------------------------------
            Return New String() {"System.Xml", "CustomDP"}
        End Function
    End Class 'CustomDirectiveProcessor


    '--------------------------------------------------------------------------
    ' the code that we are adding to the generated transformation class 
    ' will call this method
    '--------------------------------------------------------------------------
    Public Class XmlReaderHelper

        Public Shared Function ReadXml(ByVal fileName As String) As XmlDocument

            Dim d As XmlDocument = New XmlDocument()

            Using reader As XmlTextReader = New XmlTextReader(fileName)

                Try
                    d.Load(reader)

                Catch e As System.Xml.XmlException

                    Throw New DirectiveProcessorException("Unable to read the XML file.", e)
                End Try
            End Using

            Return d
        End Function
    End Class 'XmlReaderHelper

End Namespace

线程安全

此类型的任何公共 static(在 Visual Basic 中为 Shared) 成员都是线程安全的。但不保证所有实例成员都是线程安全的。

请参见

参考

Microsoft.VisualStudio.TextTemplating 命名空间

RequiresProvidesDirectiveProcessor

其他资源

创建自定义 T4 文本模板指令处理器

演练:创建自定义指令处理器