dev485.net codedom demystified beat schwegler architect evangelist.net developer group microsoft...

Post on 28-Dec-2015

218 Views

Category:

Documents

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

DEV485

.NET CodeDOM demystified

Beat Schwegler

Architect Evangelist

.NET Developer Group

Microsoft Corporation

Agenda

CodeDOMIntroduction

Assembly compilation

Source code generation

Source code parsing

Advanced conceptsTemplate based source code generation

On-the-fly proxy generation

CodeDOM scenarios

.NET Framework scenariosASP.NET assembly generation

WSDL proxy generation

Managed C++ WinForms designer

VS code wizards

Custom scenariosGeneration of typesafe collections

Source code skeleton generation

On the fly tie-pattern generation

CodeDOM namespaces

System.CodeDom Contains the Code Document Object Model (CodeDOM) graph types

System.CodeDom.CompilerContract for all CodeDomProviders

Contains interfaces and (abstract) base classes

CodeDOM providers

Microsoft providersC#, VB.NET, Managed C++, Jscript, J#

Microsoft partnersNetCOBOL (Fujitsu)

ActivePERL (ActiveState)

Eiffel (Interactive Software Engineering)

HelloWorld CodeDom graph

namespace Samples{ using System; public class Hello { public void SayHello() { Console.WriteLine("Hello World!"); } }}

CompileUnitCompileUnit

NamespacesNamespaces

Namespace Sample Namespace Sample

ImportsImports TypesTypes

Class HelloWorldClass HelloWorld

MembersMembers

Method SayHelloMethod SayHello

StatementsStatements

ExpressionExpression

SystemSystem

CodeDOM graphIndependent of programming language

In-memory representation of a source code document

Tree based object model

Doesn’t support all language specific features (no unsafe, no variable declaration lists, …)

Compiles if the root element is of type CodeCompileUnit

CodeDOM concepts

public static void Main(String[] args ){ String usr; FileStream f; StreamWriter w; try { usr=Environment.GetEnvironmentVariable("USERNAME"); f=new FileStream(“C:\\test.txt",FileMode.Create); w=new StreamWriter(f); w.WriteLine(usr); w.Close(); } catch (Exception e){ Console.WriteLine("Exception:"+e.ToString()); }}

public static void Main(String[] args ){ String usr; FileStream f; StreamWriter w; try { usr=Environment.GetEnvironmentVariable("USERNAME"); f=new FileStream(“C:\\test.txt",FileMode.Create); w=new StreamWriter(f); w.WriteLine(usr); w.Close(); } catch (Exception e){ Console.WriteLine("Exception:"+e.ToString()); }}

Source codeSource code

CompileUnitCompileUnit

NamespacesNamespaces

Namespace Sample Namespace Sample

ImportsImports TypesTypes

Class HelloWorldClass HelloWorld

MembersMembers

Method SayHelloMethod SayHello

StatementsStatements

ExpressionExpression

SystemSystem

CodeDOM graphCodeDOM graph

AssemblyAssembly

compilingcompilingCodeDOM graphCodeDOM graph

compilingcompilingsource codesource code

parsingparsingsource codesource code

generatinggeneratingsource codesource code

Programming model

Creating the code providerCodeDomProvider provider = new Microsoft.CSharp.CSharpCodeProvider();

Obtaining the required interfaceICodeGenerator generator = provider.CreateGenerator();

Calling the method

generator.GenerateCodeFromCompileUnit(…);

CodeDOM

Compiling an assembly on the flyIn-memory

stored to disk

Generating code according to an in-memory CodeDOM graph

Several code providers are already available (C#, VB.NET, J#, Managed C++)

Parsing code to get an in-memory CodeDOM graph

Agenda

CodeDOMIntroduction

Assembly compilation

Source code generation

Source code parsing

Advanced conceptsTemplate based source code generation

On-the-fly proxy generation

Assembly compilation

public static void Main(String[] args ){ String usr; FileStream f; StreamWriter w; try { usr=Environment.GetEnvironmentVariable("USERNAME"); f=new FileStream(“C:\\test.txt",FileMode.Create); w=new StreamWriter(f); w.WriteLine(usr); w.Close(); } catch (Exception e){ Console.WriteLine("Exception:"+e.ToString()); }}

public static void Main(String[] args ){ String usr; FileStream f; StreamWriter w; try { usr=Environment.GetEnvironmentVariable("USERNAME"); f=new FileStream(“C:\\test.txt",FileMode.Create); w=new StreamWriter(f); w.WriteLine(usr); w.Close(); } catch (Exception e){ Console.WriteLine("Exception:"+e.ToString()); }}

Source codeSource code

CompileUnitCompileUnit

NamespacesNamespaces

Namespace Sample Namespace Sample

ImportsImports TypesTypes

Class HelloWorldClass HelloWorld

MembersMembers

Method SayHelloMethod SayHello

StatementsStatements

ExpressionExpression

SystemSystem

CodeDOM graphCodeDOM graph

AssemblyAssembly

compilingcompilingCodeDOM graphCodeDOM graph

compilingcompilingsource codesource code

parsingparsingsource codesource code

generatinggeneratingsource codesource code

Assembly compilation

MotivationsOn-the-fly code generation and compilation

Interface interception

Compiled “scripting” support

ICodeCompiler (1/3)

Compilation sourcesCodeCompileUnit (CodeDOM graph)Source fileString containing source code

Compilation methodsSingle compilationCompileAssemblyFromDom(…)CompileAssemblyFromFile(…)CompileAssemblyFromSource(…)

Batch compilationCompileAssemblyFromDomBatch(…)CompileAssemblyFromFileBatch(…)CompileAssemblyFromSourceBatch(…)

ICodeCompiler (2/3)

Compilation parameterizationclass CompilerParameters

Compiler options

GenerateExecutable (false => dll)

GenerateInMemory

OutputAssembly

MainClass

ICodeCompiler (3/3)

Compilation resultsCompileAssemblyFrom… methods return CompileResults

CompiledAssembly, Errors, Output, …

Printing the compiler output to the screen:

CompilerResults results = compiler.CompileAssemblyFromFile(options, src);

foreach (string line in results.Output) { Console.WriteLine(line); }

Generating Generating assemblies on the flyassemblies on the fly

demodemo

Agenda

CodeDOMIntroduction

Assembly compilation

Source code generation

Source code parsing

Advanced conceptsTemplate based source code generation

On-the-fly proxy generation

Source code generation

public static void Main(String[] args ){ String usr; FileStream f; StreamWriter w; try { usr=Environment.GetEnvironmentVariable("USERNAME"); f=new FileStream(“C:\\test.txt",FileMode.Create); w=new StreamWriter(f); w.WriteLine(usr); w.Close(); } catch (Exception e){ Console.WriteLine("Exception:"+e.ToString()); }}

public static void Main(String[] args ){ String usr; FileStream f; StreamWriter w; try { usr=Environment.GetEnvironmentVariable("USERNAME"); f=new FileStream(“C:\\test.txt",FileMode.Create); w=new StreamWriter(f); w.WriteLine(usr); w.Close(); } catch (Exception e){ Console.WriteLine("Exception:"+e.ToString()); }}

Source codeSource code

CompileUnitCompileUnit

NamespacesNamespaces

Namespace Sample Namespace Sample

ImportsImports TypesTypes

Class HelloWorldClass HelloWorld

MembersMembers

Method SayHelloMethod SayHello

StatementsStatements

ExpressionExpression

SystemSystem

CodeDOM graphCodeDOM graph

AssemblyAssembly

compilingcompilingCodeDOM graphCodeDOM graph

compilingcompilingsource codesource code

parsingparsingsource codesource code

generatinggeneratingsource codesource code

Source code generation

MotivationsAvoiding repetitive coding tasks

Generation of typed collections

Pattern based code generationTie pattern implementation

Implementation of language independent code wizards and tools

Designer support

HelloWorld CodeDom graph

namespace Samples{ using System; public class Hello { public void SayHello() { Console.WriteLine("Hello World!"); } }}

CompileUnitCompileUnit

NamespacesNamespaces

Namespace Sample Namespace Sample

ImportsImports TypesTypes

Class HelloWorldClass HelloWorld

MembersMembers

Method SayHelloMethod SayHello

StatementsStatements

ExpressionExpression

SystemSystem

CodeDom elements (1/3)

CodeObjectCommon base class for most CodeDOM objects

CodeCompileUnitContainer for a CodeDOM program graph

CodeCommentRepresents a comment

CodeExpressionBase class for other code expression objects:

CodeArrayCreateExpression

CodeCastExpression

CodeMethodInvokeExpression

CodeDom elements (2/3)

CodeNamespaceRepresents a namespace declaration

CodeNamespaceImportRepresents a namespace import directive

CodeStatementBase class for other code statement objects:

CodeAssignStatement

CodeMethodReturnStatement

CodeIterationStatement

CodeDom elements (3/3)

CodeTypeMemberBase class for a member of a type:

CodeMemberField

CodeMemberMethodCodeConstructor

CodeTypeConstructor (static ctor)

CodeEntryPointMethod

CodeMemberProperty

CodeTypeReferenceRepresents a reference to a type

ICodeGenerator (1/3)

Generation sourcesCodeCompileUnit

CodeExpression

CodeNamespace

CodeStatement

CodeTypeDeclaration

Generation inputsCodeDOM element

TextWriter

Generation options

ICodeGenerator (2/3)

Generation support verificationAre arrays of arrays supported?

Can I nest multiple types?

Are goto statements supported?

CodeDomProvider provider = new CodeDomProvider provider = new Microsoft.CSharp.CSharpCodeProvider();Microsoft.CSharp.CSharpCodeProvider(); ICodeGenerator generator = provider.CreateGenerator();ICodeGenerator generator = provider.CreateGenerator(); if (generator.Supports(GeneratorSupport.NestedTypes) == false)if (generator.Supports(GeneratorSupport.NestedTypes) == false) {{ //we have a problem...//we have a problem... }}

ICodeGenerator (3/3)

Generation optionsBlank lines between members

Bracing style (“Block” or “C”)

Else on closing

Indent string

CodeGeneratorOptions options = new CodeGeneratorOptions(); options.BlankLinesBetweenMembers = true; options.BracingStyle = "C"; // options.BracingStyle = “Block"; options.ElseOnClosing = true; options.IndentString = " ";

Generating source Generating source codecode

demodemo

Agenda

CodeDOMIntroduction

Assembly compilation

Source code generation

Source code parsing

Advanced conceptsTemplate based source code generation

On-the-fly proxy generation

Source code parsing

public static void Main(String[] args ){ String usr; FileStream f; StreamWriter w; try { usr=Environment.GetEnvironmentVariable("USERNAME"); f=new FileStream(“C:\\test.txt",FileMode.Create); w=new StreamWriter(f); w.WriteLine(usr); w.Close(); } catch (Exception e){ Console.WriteLine("Exception:"+e.ToString()); }}

public static void Main(String[] args ){ String usr; FileStream f; StreamWriter w; try { usr=Environment.GetEnvironmentVariable("USERNAME"); f=new FileStream(“C:\\test.txt",FileMode.Create); w=new StreamWriter(f); w.WriteLine(usr); w.Close(); } catch (Exception e){ Console.WriteLine("Exception:"+e.ToString()); }}

Source codeSource code

CompileUnitCompileUnit

NamespacesNamespaces

Namespace Sample Namespace Sample

ImportsImports TypesTypes

Class HelloWorldClass HelloWorld

MembersMembers

Method SayHelloMethod SayHello

StatementsStatements

ExpressionExpression

SystemSystem

CodeDOM graphCodeDOM graph

AssemblyAssembly

compilingcompilingCodeDOM graphCodeDOM graph

compilingcompilingsource codesource code

parsingparsingsource codesource code

generatinggeneratingsource codesource code

Source code parsing

MotivationsEnabling iterative designer/modeling support

Source code migrationPorting source code from one language into another

There is only one problem…

CodeDomProvider csp = new Microsoft.CSharp.CSharpCodeProvider(); CodeDomProvider vbp = new Microsoft.VisualBasic.VBCodeProvider();

ICodeParser parser = csp.CreateParser(); ICodeGenerator generator = vbp.CreateGenerator();

CodeCompileUnit cu = parser.Parse(new StreamReader("Test.cs"));

generator.GenerateCodeFromCompileUnit(cu, new StreamWriter("Test.vb"),

new CodeGeneratorOptions());

…and no real solution to it

Neither VB.NET, C# nor J# CodeDomProviders implement ICodeParser

Managed C++ implements ICodeParser, but it works only in the VS.NET designer scenario

Managed C++ implements a method based parser

Returns a CodeStatementCollection

Can’t be used for whole source files

Agenda

CodeDOMIntroduction

Assembly compilation

Source code generation

Source code parsing

Advanced conceptsTemplate based source code generation

On-the-fly proxy generation

public class Listpublic class List{{ private object[] elements;private object[] elements; private int count;private int count;

public void Add(object element) {public void Add(object element) { if (count == elements.Length) Resize(count * 2);if (count == elements.Length) Resize(count * 2); elements[count++] = element;elements[count++] = element; }}

public object this[int index] {public object this[int index] { get { return elements[index]; }get { return elements[index]; } set { elements[index] = value; }set { elements[index] = value; } }}

public int Count {public int Count { get { return count; }get { return count; } }}}}

Problem statement

List intList = new List();List intList = new List();

intList.Add(1); // Argument is boxedintList.Add(1); // Argument is boxedintList.Add(2); // Argument is boxedintList.Add(2); // Argument is boxedintList.Add("Three"); // Should be an errorintList.Add("Three"); // Should be an error

int i = (int)intList[0]; // Cast requiredint i = (int)intList[0]; // Cast required

A possible solution

public class public class IntListIntList{{ private private intint[] elements;[] elements; private int count;private int count;

public void Add(public void Add(intint element) { element) { if (count == elements.Length) Resize(count * 2);if (count == elements.Length) Resize(count * 2); elements[count++] = element;elements[count++] = element; }}

public public intint this[int index] { this[int index] { get { return elements[index]; }get { return elements[index]; } set { elements[index] = value; }set { elements[index] = value; } }}

public int Count {public int Count { get { return count; }get { return count; } }}}}

IntList intList = new IntList();IntList intList = new IntList();

intList.Add(1); // No boxingintList.Add(1); // No boxingintList.Add(2); // No boxingintList.Add(2); // No boxingintList.Add("Three"); // Compile-time errorintList.Add("Three"); // Compile-time error

int i = intList[0]; // No cast requiredint i = intList[0]; // No cast required

Template based source code generation

MotivationsAvoiding the generic approach

Downcasting/boxing is expensive

Type safety can’t be guaranteed

Base class can’t be chosen for a given implementation

class A : Immutableclass A : Immutableclass A : Volatileclass A : Volatile

All this (and more) will be addressed All this (and more) will be addressed through .NET Generics as well!through .NET Generics as well!

Generating parameterized types

CompileUnitCompileUnit

NamespacesNamespaces

Namespace Sample Namespace Sample

ImportsImports TypesTypes

Class HelloWorldClass HelloWorld

MembersMembers

Method SayHelloMethod SayHello

StatementsStatements

ExpressionExpression

SystemSystem

CollectionCollectiongraph graph

public static void Main(String[] args ){ String usr; FileStream f; StreamWriter w; try { usr=Environment.GetEnvironmentVariable("USERNAME"); f=new FileStream(“C:\\test.txt",FileMode.Create); w=new StreamWriter(f); w.WriteLine(usr); w.Close(); } catch (Exception e){ Console.WriteLine("Exception:"+e.ToString()); }}

public static void Main(String[] args ){ String usr; FileStream f; StreamWriter w; try { usr=Environment.GetEnvironmentVariable("USERNAME"); f=new FileStream(“C:\\test.txt",FileMode.Create); w=new StreamWriter(f); w.WriteLine(usr); w.Close(); } catch (Exception e){ Console.WriteLine("Exception:"+e.ToString()); }}

StringCollection StringCollection

public static void Main(String[] args ){ String usr; FileStream f; StreamWriter w; try { usr=Environment.GetEnvironmentVariable("USERNAME"); f=new FileStream(“C:\\test.txt",FileMode.Create); w=new StreamWriter(f); w.WriteLine(usr); w.Close(); } catch (Exception e){ Console.WriteLine("Exception:"+e.ToString()); }}

public static void Main(String[] args ){ String usr; FileStream f; StreamWriter w; try { usr=Environment.GetEnvironmentVariable("USERNAME"); f=new FileStream(“C:\\test.txt",FileMode.Create); w=new StreamWriter(f); w.WriteLine(usr); w.Close(); } catch (Exception e){ Console.WriteLine("Exception:"+e.ToString()); }}

Int32CollectionInt32Collection

public static void Main(String[] args ){ String usr; FileStream f; StreamWriter w; try { usr=Environment.GetEnvironmentVariable("USERNAME"); f=new FileStream(“C:\\test.txt",FileMode.Create); w=new StreamWriter(f); w.WriteLine(usr); w.Close(); } catch (Exception e){ Console.WriteLine("Exception:"+e.ToString()); }}

public static void Main(String[] args ){ String usr; FileStream f; StreamWriter w; try { usr=Environment.GetEnvironmentVariable("USERNAME"); f=new FileStream(“C:\\test.txt",FileMode.Create); w=new StreamWriter(f); w.WriteLine(usr); w.Close(); } catch (Exception e){ Console.WriteLine("Exception:"+e.ToString()); }}

FooCollection FooCollection

System.StringSystem.String

System.Int32System.Int32

Nonsense.FooNonsense.Foo

Implementation tips

Parameterize the creation of the CodeDOM graph

Types

Type names

Namespace names

CodeTypeDeclaration cs = new CodeTypeDeclaration(typeName);

CodeMemberField count = new CodeMemberField(type, "count");

CodeNamespace ns = new CodeNamespace(namespaceName);

Template based source Template based source code generationcode generation

demodemo

Agenda

CodeDOMIntroduction

Assembly compilation

Source code generation

Source code parsing

Advanced conceptsTemplate based source code generation

On-the-fly proxy generation

On-the-fly proxy generation

MotivationsMethod call interception

Ensure thread safety

Logging/tracing

Tie-generationMaking an interface aware of the implementation context

Generating proxies

TypeType(Assembly(Assembly)) ProxyProxy

AssemblyAssembly

public static void Main(String[] args ){ String usr; FileStream f; StreamWriter w; try { usr=Environment.GetEnvironmentVariable("USERNAME"); f=new FileStream(“C:\\test.txt",FileMode.Create); w=new StreamWriter(f); w.WriteLine(usr); w.Close(); } catch (Exception e){ Console.WriteLine("Exception:"+e.ToString()); }}

public static void Main(String[] args ){ String usr; FileStream f; StreamWriter w; try { usr=Environment.GetEnvironmentVariable("USERNAME"); f=new FileStream(“C:\\test.txt",FileMode.Create); w=new StreamWriter(f); w.WriteLine(usr); w.Close(); } catch (Exception e){ Console.WriteLine("Exception:"+e.ToString()); }}

Source Source

CompileUnitCompileUnitNamespacesNamespaces

Namespace Sample Namespace Sample ImportsImports TypesTypes

Class HelloWorldClass HelloWorldMembersMembersMethod SayHelloMethod SayHello

StatementsStatementsExpressionExpression

SystemSystem

Proxy Proxy graphgraph

ReflectionReflection

InjectionInjection GenerationGeneration

CompilationCompilation

CompileUnitCompileUnitNamespacesNamespaces

Namespace Sample Namespace Sample ImportsImports TypesTypes

Class HelloWorldClass HelloWorldMembersMembersMethod SayHelloMethod SayHello

StatementsStatementsExpressionExpression

SystemSystem

ReflectedReflected graph graph

Implementation tips (1/5)

Only type contracts are reflectableNo managed access to implementation

Intercept interfaces not classesSimplifies programming model

Generate constructors that initialize the underlying instance Be aware of unsupported constructs

Unsafe (string’s char*)Nested namespaces

Use IsSpecialName to detect property and event methods

Implementation tips (2/5)

Interface interception

public Interface IFoo{ int foo(int i);}

public class A : B, IFoo{ public A(string name){;} public int foo(int i){;} public int doIt(){;}}

public class Proxy : C, IFoo{ private A __tieObject; public Proxy(string name) { // pre ctor injection __tieObj = new A(name); // post ctor injection } public int foo(int i) { // pre method call injection int __returnValue; __returnValue = __tieObj.foo(i); // post method call injection return __returnValue; }}

Implementation tips (3/5)

Delegates and events allow flexible code injection

public delegate void MethodCallInjection(CodeMemberMethod mm, MethodInfo mi);

public delegate void CtorCallInjection(CodeConstructor cc, ConstructorInfo ci);

public delegate void PropertyCallInjection(CodeMemberProperty mp, PropertyInfo pi);

public event MethodCallInjection OnPreMethodCallInjection;public event MethodCallInjection OnMethodCallInjection;public event MethodCallInjection OnPostMethodCallInjection;

public event CtorCallInjection OnPreCtorCallInjection;…

Implementation tips (4/5)

Injection delegate implementationpublic void ParamCheckInjection(CodeMemberMethod mm, MethodInfo mi){ foreach (ParameterInfo pi in mi.GetParameters()) { mm.Statements.Add( new CodeExpressionStatement ( new CodeMethodInvokeExpression( new CodeMethodReferenceExpression( new CodeTypeReferenceExpression("System.Console"),

"WriteLine”), new CodePrimitiveExpression(pi.Name + ": {0}"), new CodeMethodInvokeExpression(new CodeVariableReferenceExpression(pi.Name), "ToString")))); }} XmlNodeList SelectNodes(string xpath, XmlNamespaceManager nsmgr)

{ System.Console.WriteLine("xpath: {0}", xpath.ToString()); System.Console.WriteLine("nsmgr: {0}", nsmgr.ToString());

Implementation tips (5/5)

Creating an injected instance

public object CreateInstance(string typeName, params object[] args){ Type[] types = new Type[args.Length]; for (int i=0; i < args.Length; i++) { types[i] = args[i].GetType(); }

Type injectedType = compiledAssembly.GetType(typeName, true); ConstructorInfo ci = injectedType.GetConstructor(types); return ci.Invoke(args);}

IFoo iProxy = (IFoo) xxx.CreateInstance(“Proxy”, “Hello”);int s = iProxy.Foo(2);

On-the-fly proxy On-the-fly proxy generationgeneration

demodemo

Agenda

CodeDOMIntroduction

Assembly compilation

Source code generation

Source code parsing

Advanced conceptsTemplate based source code generation

On-the-fly proxy generation

Summary

Summary

Assembly compilationOn-the-fly code generation and compilation

Source code generationAvoiding repetitive coding tasksPattern based code generationImplementation of language independent code wizards and tools

Source code parsingEnabling iterative designer/modeling supportSource code migration

Ask The ExpertsGet Your Questions Answered

I will be available in the ATE area after this session

Community Resources

Community Resourceshttp://www.microsoft.com/communities/default.mspx

Most Valuable Professional (MVP)http://www.mvp.support.microsoft.com/

NewsgroupsConverse online with Microsoft Newsgroups, including Worldwidehttp://www.microsoft.com/communities/newsgroups/default.mspx

User GroupsMeet and learn with your peershttp://www.microsoft.com/communities/usergroups/default.mspx

evaluationsevaluations

© 2003 Microsoft Corporation. All rights reserved.© 2003 Microsoft Corporation. All rights reserved.This presentation is for informational purposes only. MICROSOFT MAKES NO WARRANTIES, EXPRESS OR IMPLIED, IN THIS SUMMARY.This presentation is for informational purposes only. MICROSOFT MAKES NO WARRANTIES, EXPRESS OR IMPLIED, IN THIS SUMMARY.

top related