Presentation is loading. Please wait.

Presentation is loading. Please wait.

DEV485.NET CodeDOM demystified Beat Schwegler Architect Evangelist.NET Developer Group Microsoft Corporation.

Similar presentations


Presentation on theme: "DEV485.NET CodeDOM demystified Beat Schwegler Architect Evangelist.NET Developer Group Microsoft Corporation."— Presentation transcript:

1 DEV485.NET CodeDOM demystified Beat Schwegler Architect Evangelist.NET Developer Group Microsoft Corporation

2 Agenda CodeDOM Introduction Assembly compilation Source code generation Source code parsing Advanced concepts Template based source code generation On-the-fly proxy generation

3 CodeDOM scenarios.NET Framework scenarios ASP.NET assembly generation WSDL proxy generation Managed C++ WinForms designer VS code wizards Custom scenarios Generation of typesafe collections Source code skeleton generation On the fly tie-pattern generation

4 CodeDOM namespaces System.CodeDom Contains the Code Document Object Model (CodeDOM) graph types System.CodeDom.Compiler Contract for all CodeDomProviders Contains interfaces and (abstract) base classes

5 CodeDOM providers Microsoft providers C#, VB.NET, Managed C++, Jscript, J# Microsoft partners NetCOBOL (Fujitsu) ActivePERL (ActiveState) Eiffel (Interactive Software Engineering) …

6 HelloWorld CodeDom graph namespace Samples { using System; public class Hello { public void SayHello() { Console.WriteLine("Hello World!"); } CompileUnit Namespaces Namespace Sample Imports System Types Class HelloWorld Members Method SayHello Statements Expression

7 CodeDOM graph Independent 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

8 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 code CodeDOM graph Assembly compiling compiling source code parsing source code generating

9 Programming model Creating the code provider CodeDomProvider provider = new Microsoft.CSharp.CSharpCodeProvider(); Obtaining the required interface ICodeGenerator generator = provider.CreateGenerator(); Calling the method generator.GenerateCodeFromCompileUnit(…);

10 CodeDOM Compiling an assembly on the fly In-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

11 Agenda CodeDOM Introduction Assembly compilation Source code generation Source code parsing Advanced concepts Template based source code generation On-the-fly proxy generation

12 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 code CodeDOM graph Assembly compiling compiling source code parsing source code generating

13 Assembly compilation Motivations On-the-fly code generation and compilation Interface interception Compiled “scripting” support

14 ICodeCompiler (1/3) Compilation sources CodeCompileUnit (CodeDOM graph) Source file String containing source code Compilation methods Single compilation CompileAssemblyFromDom(…) CompileAssemblyFromFile(…) CompileAssemblyFromSource(…) Batch compilation CompileAssemblyFromDomBatch(…) CompileAssemblyFromFileBatch(…) CompileAssemblyFromSourceBatch(…)

15 ICodeCompiler (2/3) Compilation parameterization class CompilerParameters Compiler options GenerateExecutable (false => dll) GenerateInMemory OutputAssembly MainClass …

16 ICodeCompiler (3/3) Compilation results CompileAssemblyFrom… 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); }

17 Generating assemblies on the fly demo demo

18 Agenda CodeDOM Introduction Assembly compilation Source code generation Source code parsing Advanced concepts Template based source code generation On-the-fly proxy generation

19 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 code CodeDOM graph Assembly compiling compiling source code parsing source code generating

20 Source code generation Motivations Avoiding repetitive coding tasks Generation of typed collections Pattern based code generation Tie pattern implementation Implementation of language independent code wizards and tools Designer support

21 HelloWorld CodeDom graph namespace Samples { using System; public class Hello { public void SayHello() { Console.WriteLine("Hello World!"); } CompileUnit Namespaces Namespace Sample Imports System Types Class HelloWorld Members Method SayHello Statements Expression

22 CodeDom elements (1/3) CodeObject Common base class for most CodeDOM objects CodeCompileUnit Container for a CodeDOM program graph CodeComment Represents a comment CodeExpression Base class for other code expression objects: CodeArrayCreateExpression CodeCastExpression CodeMethodInvokeExpression …

23 CodeDom elements (2/3) CodeNamespace Represents a namespace declaration CodeNamespaceImport Represents a namespace import directive CodeStatement Base class for other code statement objects: CodeAssignStatement CodeMethodReturnStatement CodeIterationStatement …

24 CodeDom elements (3/3) CodeTypeMember Base class for a member of a type: CodeMemberField CodeMemberMethod CodeConstructor CodeTypeConstructor (static ctor) CodeEntryPointMethod CodeMemberProperty … CodeTypeReference Represents a reference to a type

25 ICodeGenerator (1/3) Generation sources CodeCompileUnit CodeExpression CodeNamespace CodeStatement CodeTypeDeclaration Generation inputs CodeDOM element TextWriter Generation options

26 ICodeGenerator (2/3) Generation support verification Are arrays of arrays supported? Can I nest multiple types? Are goto statements supported? … CodeDomProvider provider = new Microsoft.CSharp.CSharpCodeProvider(); CodeDomProvider provider = new 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... }

27 ICodeGenerator (3/3) Generation options Blank 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 = " ";

28 Generating source code demo demo

29 Agenda CodeDOM Introduction Assembly compilation Source code generation Source code parsing Advanced concepts Template based source code generation On-the-fly proxy generation

30 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 code CodeDOM graph Assembly compiling compiling source code parsing source code generating

31 Source code parsing Motivations Enabling iterative designer/modeling support Source code migration Porting source code from one language into another

32 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());

33 …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

34 Agenda CodeDOM Introduction Assembly compilation Source code generation Source code parsing Advanced concepts Template based source code generation On-the-fly proxy generation

35 public 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(); intList.Add(1); // Argument is boxed intList.Add(2); // Argument is boxed intList.Add("Three"); // Should be an error int i = (int)intList[0]; // Cast required

36 A possible solution public class IntList { private int[] elements; private int[] elements; private int count; private int count; public void Add(int element) { public void Add(int element) { if (count == elements.Length) Resize(count * 2); if (count == elements.Length) Resize(count * 2); elements[count++] = element; elements[count++] = element; } public int this[int index] { public int 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.Add(1); // No boxing intList.Add(2); // No boxing intList.Add("Three"); // Compile-time error int i = intList[0]; // No cast required

37 Template based source code generation Motivations Avoiding 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 : Immutable class A : Volatile All this (and more) will be addressed through.NET Generics as well!

38 Generating parameterized types Collectiongraph 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 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()); } Int32Collection 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()); } FooCollectionSystem.String System.Int32 Nonsense.Foo

39 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);

40 Template based source code generation demo demo

41 Agenda CodeDOM Introduction Assembly compilation Source code generation Source code parsing Advanced concepts Template based source code generation On-the-fly proxy generation

42 Motivations Method call interception Ensure thread safety Logging/tracing Tie-generation Making an interface aware of the implementation context

43 Generating proxiesType (Assembly) ProxyAssembly 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 Proxy graph Reflection Injection Generation Compilation Reflected graph

44 Implementation tips (1/5) Only type contracts are reflectable No managed access to implementation Intercept interfaces not classes Simplifies 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

45 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; }

46 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; …

47 Implementation tips (4/5) Injection delegate implementation public 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());

48 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);

49 On-the-fly proxy generation demo demo

50 Agenda CodeDOM Introduction Assembly compilation Source code generation Source code parsing Advanced concepts Template based source code generation On-the-fly proxy generation Summary

51 Assembly compilation On-the-fly code generation and compilation Source code generation Avoiding repetitive coding tasks Pattern based code generation Implementation of language independent code wizards and tools Source code parsing Enabling iterative designer/modeling support Source code migration

52 Ask The Experts Get Your Questions Answered I will be available in the ATE area after this session

53 Community Resources http://www.microsoft.com/communities/default.mspx Most Valuable Professional (MVP) http://www.mvp.support.microsoft.com/ Newsgroups Converse online with Microsoft Newsgroups, including Worldwide http://www.microsoft.com/communities/newsgroups/default.mspx User Groups Meet and learn with your peers http://www.microsoft.com/communities/usergroups/default.mspx

54 evaluations evaluations

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


Download ppt "DEV485.NET CodeDOM demystified Beat Schwegler Architect Evangelist.NET Developer Group Microsoft Corporation."

Similar presentations


Ads by Google