{"id":215,"date":"2011-02-11T15:49:19","date_gmt":"2011-02-11T15:49:19","guid":{"rendered":"http:\/\/www.ericwhite.com\/home2\/bm8qcmjy\/public_html\/blog\/?p=215"},"modified":"2011-02-24T22:57:08","modified_gmt":"2011-02-24T22:57:08","slug":"simulating-virtual-extension-methods","status":"publish","type":"post","link":"https:\/\/www.ericwhite.com\/blog\/2011\/02\/11\/simulating-virtual-extension-methods\/","title":{"rendered":"Simulating Virtual Extension Methods"},"content":{"rendered":"<p>When considering the problem of how to generate code that will create some arbitrary XML tree, it is interesting to examine the LINQ to XML class hierarchy, which uses polymorphism. The <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb351756.aspx\">XObject<\/a> class is an abstract base class of both the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.xml.linq.xattribute.aspx\">XAttribute<\/a> and <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.xml.linq.xnode.aspx\">XNode<\/a> classes. The XNode class is an abstract base class of <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.xml.linq.xcontainer.aspx\">XContainer<\/a>, <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.xml.linq.xcomment.aspx\">XComment<\/a>, <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.xml.linq.xdocumenttype.aspx\">XDocumentType<\/a>, <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.xml.linq.xprocessinginstruction.aspx\">XProcessingInstruction<\/a>, and <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.xml.linq.xtext.aspx\">XText<\/a>. XContainer is the base class for <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.xml.linq.xelement.aspx\">XElement<\/a> and <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.xml.linq.xdocument.aspx\">XDocument<\/a>.<\/p>\n<p>This post is the sixth in a series of blog posts. Here is the complete list: <a href=\"https:\/\/www.ericwhite.com\/blog\/map\/generating-open-xml-wordprocessingml-documents-blog-post-series\/\">Generating Open XML WordprocessingML Documents Blog Post Series<\/a><\/p>\n<p>The following diagram shows the class hierarchy of the LINQ to XML classes that are important when considering serializing a LINQ to XML tree as code. There are other classes in LINQ to XML, but they don\u2019t impact this discussion.<\/p>\n<p><a href=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/Image1.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;\" title=\"Image1\" src=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/Image1_thumb.png\" border=\"0\" alt=\"Image1\" width=\"634\" height=\"335\" \/><\/a><\/p>\n<p>Software systems such as LINQ to XML are typically written using a recursive approach. The XNode class has an abstract virtual method WriteTo. Each derived class must override the WriteTo method and provide its own method for serializing. When serializing an XElement object by calling WriteTo, internally, LINQ to XML calls the WriteTo method for each of the child nodes of the XElement object. This is the approach that we want to use when generating code to create an arbitrary XML tree.<\/p>\n<p>What would be ideal is to write \u2018Virtual Extension Methods\u2019. There would be an abstract virtual extension method for XObject named ToCode. This extension method would be overridden in each of the concrete classes. Classes that include child objects, such as XElement and XDocument can then iterate through their children and use the virtual extension method to convert each node in the XML tree to the appropriate C# code to create the node.<\/p>\n<p>However, C# does not include support for the idea of a virtual extension method. When you call an extension method, it is bound at compile time to an extension method based on the type of the variable, not based on the type of the object in the variable. To show exactly what I mean, consider the following snippet:<br \/>\n<code><br \/>\npublic&nbsp;static&nbsp;class&nbsp;MyExtensions<br \/>\n{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;string&nbsp;ToCode(this&nbsp;XObject&nbsp;o)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;\"Called&nbsp;extension&nbsp;method&nbsp;on&nbsp;XObject\";<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;string&nbsp;ToCode(this&nbsp;XElement&nbsp;e)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;\"Called&nbsp;extension&nbsp;method&nbsp;on&nbsp;XElement\";<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;}<br \/>\n}<\/p>\n<p>class&nbsp;Program<br \/>\n{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;void&nbsp;Main(string[]&nbsp;args)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XElement&nbsp;e&nbsp;=&nbsp;new&nbsp;XElement(\"Root\");<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(e.ToCode());<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XObject&nbsp;o&nbsp;=&nbsp;e;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(o.ToCode());<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;}<br \/>\n}<br \/>\n<\/code><\/p>\n<p>The above snippet calls the ToCode extension method twice for the same object. However, even though the type of the object is XElement, when the object is assigned to a variable with type XObject (which is valid because XElement is derived from XNode, which derives from XObject), and the program calls the ToCode extension method, the extension method on XElement is not called. Instead, the extension method on XObject is called.<\/p>\n<p>Because the LINQ to XML programming interface is fairly simple, we can simulate virtual extension methods by implementing an extension method on XObject that simply dispatches to the appropriate extension method based on the actual type of the object. The following listing shows the implementation of the ToCode extension method for XObject.<br \/>\n<code><br \/>\npublic&nbsp;static&nbsp;string&nbsp;ToCode(this&nbsp;XObject&nbsp;xObject)<br \/>\n{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;XAttribute&nbsp;a&nbsp;=&nbsp;xObject&nbsp;as&nbsp;XAttribute;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(a&nbsp;!=&nbsp;null)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;a.ToCode();<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;XElement&nbsp;element&nbsp;=&nbsp;xObject&nbsp;as&nbsp;XElement;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(element&nbsp;!=&nbsp;null)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;element.ToCode();<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;XCData&nbsp;cdata&nbsp;=&nbsp;xObject&nbsp;as&nbsp;XCData;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(cdata&nbsp;!=&nbsp;null)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;cdata.ToCode();<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;XText&nbsp;text&nbsp;=&nbsp;xObject&nbsp;as&nbsp;XText;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(text&nbsp;!=&nbsp;null)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;text.ToCode();<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;XComment&nbsp;comment&nbsp;=&nbsp;xObject&nbsp;as&nbsp;XComment;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(comment&nbsp;!=&nbsp;null)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;comment.ToCode();<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;XProcessingInstruction&nbsp;pi&nbsp;=&nbsp;xObject&nbsp;as&nbsp;XProcessingInstruction;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(pi&nbsp;!=&nbsp;null)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;pi.ToCode();<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;CodeGenerationException(\"Internal&nbsp;error\");<br \/>\n}<br \/>\n<\/code><\/p>\n<p>Next, we can examine the ToCode method that is implemented on XAttribute. The code calls an Indentation method that determines the number of spaces to precede the \u2018new XAttribute\u2019. This enables the code to be properly indented, so that it is easy to examine the generated code. Other than this, it is pretty straightforward code to generate the code to new up an XAttribute object.<br \/>\n<code><br \/>\npublic&nbsp;static&nbsp;string&nbsp;ToCode(this&nbsp;XAttribute&nbsp;attribute)<br \/>\n{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;Indentation(attribute)&nbsp;+<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String.Format(\"new&nbsp;XAttribute(\\\"{0}\\\",&nbsp;\\\"{1}\\\"),\"&nbsp;+&nbsp;Environment.NewLine,<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;attribute.Name,&nbsp;attribute.Value);<br \/>\n}<br \/>\n<\/code><\/p>\n<p>As initially written, the generated code to create an XAttribute or XElement object includes appending the comma before the new line.\u00a0 One minor issue that must be solved is that when passing a number of parameters to a function that takes a params array, a comma immediately before the closing parenthesis is invalid.<\/p>\n<p><a href=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/Image2.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;\" title=\"Image2\" src=\"https:\/\/www.ericwhite.com\/blog\/wp-content\/uploads\/2011\/02\/Image2_thumb.png\" border=\"0\" alt=\"Image2\" width=\"622\" height=\"176\" \/><\/a><\/p>\n<p>The approach I took to solve this problem is that after assembling all of the code to create the child nodes of an XElement object, the code calls a method to trim off the final comma.<br \/>\n<code><br \/>\npublic&nbsp;static&nbsp;string&nbsp;ToCode(this&nbsp;XElement&nbsp;element)<br \/>\n{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;c&nbsp;=&nbsp;element.Attributes().Cast&lt;XObject&gt;().Concat(element.Nodes().Cast&lt;XObject&gt;());<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(c.Count()&nbsp;==&nbsp;0)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;Indentation(element)&nbsp;+<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String.Format(\"new&nbsp;XElement(\\\"{0}\\\"),\"&nbsp;+&nbsp;Environment.NewLine,&nbsp;element.Name);<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;else<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;Indentation(element)&nbsp;+<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String.Format(\"new&nbsp;XElement(\\\"{0}\\\",\"&nbsp;+&nbsp;Environment.NewLine,&nbsp;element.Name)&nbsp;+<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TrimFinalComma(c.Select(n&nbsp;=&gt;&nbsp;n.ToCode()).StringConcatenate())&nbsp;+<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Indentation(element)&nbsp;+&nbsp;\"),\"&nbsp;+&nbsp;Environment.NewLine;<br \/>\n}<br \/>\n<\/code><\/p>\n<p>TrimFinalComma looks like this:<br \/>\n<code><br \/>\nprivate&nbsp;static&nbsp;string&nbsp;TrimFinalComma(string&nbsp;code)<br \/>\n{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(code.EndsWith(\",\"&nbsp;+&nbsp;Environment.NewLine))<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;code.Substring(0,&nbsp;code.Length&nbsp;-&nbsp;(\",\"&nbsp;+&nbsp;Environment.NewLine).Length)&nbsp;+<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Environment.NewLine;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;code;<br \/>\n}<br \/>\n<\/code><\/p>\n<p>You can see the rest of the ToCode extension methods in <a href=\"https:\/\/www.ericwhite.com\/blog\/2011\/02\/07\/generating-c-code-from-an-xml-tree-using-virtual-extension-methods\/\">Generating C# code from an XML Tree using Virtual Extension Methods<\/a>.<\/p>\n<h1>One Final Note<\/h1>\n<p>Some people will recognize the similarity in functionality between the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb397977.aspx\">Paste XML as LINQ<\/a> sample and the code presented in this and the last post.\u00a0 The code presented in the Paste XML as LINQ sample is imperative code that iterates through the nodes outputting code.\u00a0 I need a completely different structure for my code.\u00a0 By coding as a recursive functional transform, I can easily alter the transform as appropriate for special purpose content controls that contain C#.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Discusses how I similated &#8216;virtual extension methods&#8217; to write code to generate code to create an arbitrary XML tree.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"_s2mail":"","footnotes":""},"categories":[7,8,3,5],"tags":[],"class_list":["post-215","post","type-post","status-publish","format-standard","hentry","category-document-generation-series","category-functional-programming","category-open-xml","category-wordprocessingml"],"_links":{"self":[{"href":"https:\/\/www.ericwhite.com\/blog\/wp-json\/wp\/v2\/posts\/215","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.ericwhite.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.ericwhite.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.ericwhite.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ericwhite.com\/blog\/wp-json\/wp\/v2\/comments?post=215"}],"version-history":[{"count":10,"href":"https:\/\/www.ericwhite.com\/blog\/wp-json\/wp\/v2\/posts\/215\/revisions"}],"predecessor-version":[{"id":255,"href":"https:\/\/www.ericwhite.com\/blog\/wp-json\/wp\/v2\/posts\/215\/revisions\/255"}],"wp:attachment":[{"href":"https:\/\/www.ericwhite.com\/blog\/wp-json\/wp\/v2\/media?parent=215"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ericwhite.com\/blog\/wp-json\/wp\/v2\/categories?post=215"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ericwhite.com\/blog\/wp-json\/wp\/v2\/tags?post=215"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}