Codedom with Delphi IDE

xiaoxiao2021-03-06  90

The codedom and the

Delphi

Idea

By Corbin Dunn

Borland R & D Software Engineer

CDunn@borland.com

translation:

Visli

What is CodeDom?

CodeDom is an abbreviation of code document object model, which allows .NET developers to generate and compile source code at runtime in multiple languages. Codedom is a collection of classes for describing the source code. Once the source code is described as CODEDOM, it can be printed, compiled into a assembly language, or compile into memory and execute. The application can also use Codedom to serve as an abstraction layer of the source code without having to have internal knowledge of the following language.

WinForms / WebForms designer

Codedom uses WinForms and WebForms designers in the .NET framework. THESE Designers Require a Codedom to Be, And Walk The

DOM

looking for types that can be designed. Once a type is found, they look for the InitializeComponents method and walk each statement in the method, executing them as it does along. The end result is a deserialized form (or web) designer.

When changes are made to the form designer, the current state of the designer is flushed out to a CodeDOM object. This object can then be injected back into the original source code. By using an abstract set of classes, the WinForms and WebForms designers do NOT NEED TO KNOW Anything About The Underlying Programming Language.

ASP.

Net

ASP.

Net

Also uses the codedom. when

ASPX

Pages Have Source Code Mixed in, The ASP.

Net

ENGINE MUSOME How Compile THIS Source. One of the Underlying Problems STEMS from The Fact That

ASPX

Page in A Variety of Different Languages. in Order To Keep IT Well Abstract, The ASP.

Net

engine creates a CodeDOM for the page. The CodeDOM is language independent, making the engine able to manipulate any language that has a CodeDOM provider. It can then compile the CodeDOM to an assembly, execute it, and return the resulting HTML.

Codedom foundation

It is quite simple to use Codedom. But I have to master it, I strongly recommend reading the help:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpcongeneratingCompilingSourceCodedynamicalLinmultipleLanguages.asp In addition, Codedom Quick Reference is also essential:

Http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpConcodedomquickreference.asp

Codedom overview

System.codedom namespace contains all classes for constructing a CodeDom. The base package is as follows:

CodeCompileUnit

Encircle all and in the top of the Codedom object. It mainly includes one or more CodeNameSpace objects.

Codenamespace

A name space is depicted in the source code. The name space can be included in its internal type, each type is a CodeTypedecLaration or its sub-generation.

CODETYPEDECLATION

The basic CodeTypeDeclaration is used to represent classes, enumerations, interfaces, and structures (records). A CodeTypeDelegate is used to represent a delegate (which is an event declaration). The CodeTypeDeclaration contains CodeTypeMembers to represent the members in the type.

CodeTypemember

This is the base abstract class for all type members There are things to represent all basic code members, including: CodeMemberMethod, CodeMemberField, CodeMemberProperty, CodeConstructor, and a CodeTypeConstructor (a class constructor) Most CodeTypeMembers can have attributes applied to them; this.. IS DONE VIA A CodeAttributedeclaration, Which, Unlike Most All The Other Classes, Does Not Descend from CodeObject.

CodeAttributeDeclaration

This class allows you to specify an attribute. It is attribute, and any arguments passed to it (Which is also represented by codeDom Objects).

CodememberMethod

The CodeMemeMethod Contains Statements Each of Which Are An Instance of a CodeState Object.

Codestatement

The CodeStatement is the base class for all statements. There are CodeAssignStatement, CodeConditionStatement (used for if or while) along with many others. Each statement is generally made of up expressions (or it is an expression, with the CodeExpressionStatement), represented by the CodeExpression Abstract Class.codeExpression

Represents all expressions. Expressions include ways of referencing fields, properties, and variables (CodeFieldReferenceExpression, CodePropertyReferenceExpression, and CodeVariableReferenceExpression), along with ways of invoking events, or referencing primitive values ​​(such as integers, or strings).

Codesnippetxxx

The CodeSnippetXXX classes (such as CodeSnippetExpression) are useful for representing a snippet of source code that can not be represented in the CodeDOM. The problem with snippets is that they are language dependent.

CodeObject

The CodeObject class is the base abstract class for most all of the other CodeDOM classes The main thing that it introduces is the UserData property;. Allowing a user of the CodeDOM to store information in a particular CodeObject.

But what can you do with codedom Objects overce you have created the system.codedom.compiler namespace HAS MOSTOTE CLASS AND interfacket used to do victings with a cotedom.

One thing you may want to do, is print the CodeDOM in a particular language. To do this, you must get a code generator (ICodeGenerator) for that particular language. An ICodeGenerator is generally acquired through a CodeDomProvider. A CodeDomProvider also allows you to Create a code compiler (icodecompiler) to Compile The Code.

For Example of this, see the incruded source code.

Creating a cotedom in

Delphi

Code

Create a CodeDOM is very easy You first create a CodeCompileUnit (since it contains everything else) and then add a namespace to it The namespace can then specify what other namespaces (or units) that it uses:.. Var

Namespace: CODENAMESPACE;

Begin

// Create The Primary Code Unit That Contains Everything

FcodeUnit: = CodeCompileUnit.create;

// Create a namespace and add it to what unit

Namespace: = CODENAMESPACE.CREATE ('myunitname');

FcodeUnit.Namespaces.Add (Namespace);

// add a few items to the "buy" clause

Namespace.imports.add (

CODENAMESPACEIMPORT.CREATE ('system.collections');

Namespace.imports.add (

CodenamespaceImport.create ('system.data'));

Namespace.imports.add (

CODENAMESPACEIMPORT.CREATE ('system.xml'));

...

Unfortunately, One of the DrawBacks of Using The Codedom Is That Doesn't Know About The

Delphi

Language. There is no way to specify for a codenamespaceImport to be in the implementation section's buy.

The next thing you will want to do is add one ore more types to the CodeDOM. The CodeDOM has no knowledge of global procedures or units, so unfortunately there is no way of adding them at this time (although, this may change at some later TIME).

VAR

...

Mytype: CODETYPEDECLAration;

Begin

...

// Create a type and add it to the namespace

Mytype: = CODETYPEDECLATION.CREATE ('TMYCLASS');

Namespace.Types.Add (mytype);

...

A Blank Type ISN't Very Interesting, SO You Probably Should Add Some Members to IT:

VAR

...

Mymethod: CodeMemeMethod;

Myfield: CodeMemberfield;

Begin

...

// now add a field to the members in the Type

Myfield: = codememberfield.create ('Integer', 'FINT');

Mytype.members.add (myfield); // Create Method to Put in this Type

Mymethod: = codememberMethod.create;

Mymethod.name: = 'mymethod';

Mytype.members.add (mymethod);

The Real Interesting Part Is Adding Statements and Expressions To the Method:

VAR

...

Statement: CodeStatement;

Leftexpr, RightExpr: CodeExpression;

Methodexpr: CodeExpression;

Target: CODETYPEREFERENCEEXPRESSION;

Varreference: CodeVariablereferenceExpression;

Begin

...

// Create a variable, and assign a value to it.

Statement: = CodeVariableDeclarationStatement.create ('string ",

'Localstr');

Mymethod.statements.add (statement);

// Assign a value to That Variable

Leftexpr: = CodevariablereferenceExpression.create ('localstr');

RightExpr: = CodePrimitiveExpression.create ('LocalValue');

Statement: = CodeassignStatement.create (LefTexpr, RightExpr);

Mymethod.statements.add (statement);

// Write It Out to the console

Target: = CODETYPEREFERENCEEXPIPRESSION.CREATE ('system.console');

Varreference: = CodeVariableReferenceExpression.create ('localstr ");

MethodeXpr: = CodeMethodInvokeExpression.create

Target, // the thing we are calling on

'Writeline', // The Method We Are Going to Call

[VARREFERENCE]); // Parameters

MyMethod.Statements.Add (MethodeXPR);

...

Database.

Printing a code

Now That You Have a Codedom You Probably Want To Do Something With It. Printing It Is as Simple As Selecting The CodeDomprovider for The Language of Your Choice, And Printing It Out:

VAR

Provider: CodedomproVider;

Generator: icodenerator;

GENERATOROPTIONS: CODEGENERATOROPTION; Writer: Textwriter;

Builder: StringBuilder;

Begin

// Print The Code in Delphi

IF fcodeunit = nil dam

EXIT;

Provider: = DelphicodeProvider.create

// Create a Writer to Output To

Builder: = StringBuilder.create;

Writer: = StringWriter.create (Builder);

// and options to control printing

GENERATOROPTIONS: = CodeGeneratorOptions.create;

GeneratorOptions.indentstring: = '';

GeneratorOptions.bracingstyle: = 'c';

GeneratorOptions.blanklinesbetWeenMembers: = TRUE;

Generator: = provider.creategenerator;

Generator.generatecodefromCompileunit (FcodeUnit, Writer,

GeneratorOptions;

// Get the text this Was Written Out

TextBox1.text: = builder.toString;

END;

This example uses the ICodeGenerator.GenerateCodeFromCompileUnit method to print out the whole CodeCompileUnit. Additionally, you can use some of the other methods on ICodeGenerator to print just expressions, statements, etc.

Compiableing and executing

Another Cool Thing You Can do with a codedom is Compile It or Execute It. The Codedomprovider of Your Choice Can Give An iCodeCompiler That Can Be Used To Compile The Source:

VAR

Compiler: icodecompiler;

Parameters: CompilerParameters;

Results: CompilerResults;

Begin

// Create an assembly from the code unit

Compiler: = CsharpcodeProvider.create.createCompiler;

Parameters: = compilerParameters.create

['mscorlib.dll', 'system.dll', 'system.data.dll'],

'Newassembly.dll');

Results: = compiler.compileassemblyFromDom (parameters, fcodeunit);

IF results.errors.count> 0 THEN

MessageBox.show ('Could Not Compile Unit:'

Results.errors [0]. ErrorText);

End; for sale your code, if you use type, res "integer" in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, Ltd.

Delphi

or "int" in C #, then you will have to use that compiler to compile your source. Or, if you use CodeSnippetXXX CodeObjects then the snippets are placed directly in the compiled source code, and must be in the same target language. If you Stick to Fairly Safe Codedom Expressions, And Use Types Found in The

CLR

, the you will be safe.

For a Complete Example of All these Concepts, Take a Look At the include Project,

Delphi

Domprinter.bdsproj.

The CodeDom and

Delphi

The delphiprovider

THE CODEDOMPROVIDER IS The Base Factory Class That Provides A Way of Accessing An iCODECMPILER AND ICODEGENERATOR. This allows you to responsively Compile and print code in a particular language.

The.

Net

Framework includes generators for C #, VB, and Java (MS style). To use the C # or VB one, all you have to do is use the Microsoft.CSharp or Microsoft.VisualBasic namespace. To use the Java one, you must use Microsoft .Vjsharp and reason the assembly vjsharpcodeProvider.dll.

Borland Has Provided a CodeDomProvider To Use for

Delphi

TO USE It, You Must Reference The assembly delphiprovider.dll and use the namespace borland.delphi.

WinForms / WebForms Only?

One Thing to Be aware of Is That The Codedom Is Available for General Vcl for.

Net

Developments, And NOT JUST WINFORMS or WebForms. Since The Codedom Classes and Interfaces Are IN The Base.

Net

.

Using the codedom in there

Delphi

Idea

You May Have Noticed That The CodeDomProvider Has a CreateParser Method on It. Unfortunately, All of the Standard Codedomproviders (Including Thedelphi

One) Do Not Implement This Interface. So, There Is No Easy Way for An External Application To Go from Source Code To a CodeDom. But, Borland Implement A Parser for C # and

Delphi

To create a codeom, and inside the

BDS

Ide you can access it.

Using the OpenTools

API

To Access the Codedom

You can create an opentools

API

(OTA) Plug-in That Utilizes The

Delphi

And C # cotedom's from inside the

BDS

Ide.

Look at The Sample Project for The Implementation Details of Exactly How To create An Ota Plug-in, if you are not familiar with how to do so.

To Install the Plug-in INTO The IDE, Start Regedit, Andd A String Value Under The Key At:

HKCU / Software / Borland /

BDS

/ (your version) / KNown IDE Assembly

Set the name to your plug in assembly's location (IE: $

BDS

) /bin/myplugin.dll) and set the value to anything but An Empty string (IE: "My IDE Assembly").

Reading the codedom

Only Can Only Get A

DOM

From Files That Area Worry, It is Possible To Open Files Using The IotamoduleService. An Opened File In The Ide IS Represented by An iotamodule.

ONCE you have an otamodule, you can query for the IotacodeMProvider Interface:

VAR

CurrentModule: Iotamodule;

Provider: IotacodeDomProvider;

DOMFILE: IoTacodeDomfile;

Begin

CurrentModule: = Borlandide.ModuleServices.currentModule;

Provider: =

IotacodeDomprovider

CurrentModule.getService (IoTacodeDomprovider));

If the module does not support a CodeDOM, it will return nil After you have the provider, you can access the IOTACodeDomFile from it It is always good to check for nil in this case too:.. If Provider <> nil then

Begin

DOMFILE: = provider.codedomfile;

IF Domfile <> nil dam

... // Do Something with The Domfile

END;

Once you have anotacodedomfile, you can finly get a code

MyCompileUnit: = CodeCompileUnit (Domfile.getdom);

IT Is That Easy! You Can Now Do Things, Like Walk All the namespaces and types in That CodeDom, Doing WhatVer Operations you want to it.

Browsing the codedom

Let's say that you want to know what line and column a particular CodeMemberMethod is That's easy;. You can use the CodeTypeMember.LinePragma property But, an examination of the CodeLinePragma type reveals that it only has the FileName and LinNumber for the given member.; There is no colorn information!

To Handle this Situation,

BDS

Produced Codedom's Have Special UserData Added To The CodeObject.UserData Property. if You Access CodeMemethod.userData ['line'] and codedata ['

COL

'] You can get the line and coloration body! This is howate it ..

Committing changes

Once you have made some changes to the CodeDOM, you will probably want to commit those changes back to source code in the IDE. You can easily do this with the IOTACodeDomFile.WriteDom (...) method. The first parameter to WriteDom is the

DOM

You want to commit. The second parameter is the formatting options you want to use; if you pass nil, the default IDE Options Will be available.

IMPORTANT NOTES

............ ..

· Things Which Can't Be Reperesented in The CodeDom Arene Ignored (IE: Global Procedures)

· The

Delphi

Codedom Can Only Ever Contain One Namespace. Attempting To Add ANother Namespace to It Will BE IGNORED.

· When committing a CodeDOM to the IDE, the underlying source code can not have had changes made to it since you requested the CodeDOM. It is best to always grab a fresh CodeDOM from the IOTACodeDomFile, make your changes, and then immediately commit the changes to The IotacodeDomfile.

Conclusion

Well, That's it! You shouth now..............

Be Sure to Take a Look at The Example Code for a Tutorial of How To Use the codedom; Both from A Stand Alone Application, And An Ide Plug-in Wizard.

转载请注明原文地址:https://www.9cbs.com/read-98041.html

New Post(0)