<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Iron Curt : DynamicDataTable</title><link>http://blogs.msdn.com/curth/archive/tags/DynamicDataTable/default.aspx</link><description>Tags: DynamicDataTable</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>DynamicDataTable, Part 1</title><link>http://blogs.msdn.com/curth/archive/2009/05/23/dynamicdatatable-part-1.aspx</link><pubDate>Sun, 24 May 2009 07:25:59 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9638337</guid><dc:creator>curth</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/curth/comments/9638337.aspx</comments><wfw:commentRss>http://blogs.msdn.com/curth/commentrss.aspx?PostID=9638337</wfw:commentRss><description>&lt;p&gt;Let’s &lt;a href="http://blogs.msdn.com/curth/archive/2009/05/21/dynamicdatatable-part-0.aspx"&gt;get started&lt;/a&gt; by doing “the simplest thing that could possibly work”. &lt;/p&gt;  &lt;pre style="font-family: consolas; background: black; color: white; font-size: 10pt; font-weight: bold"&gt;    &lt;span style="color: #cc7832"&gt;public class&lt;/span&gt; &lt;span style="color: #ffc66d"&gt;DynamicDataTable&lt;/span&gt; : &lt;span style="color: #ffc66d"&gt;DynamicObject&lt;/span&gt; {
        &lt;span style="color: #cc7832"&gt;private readonly&lt;/span&gt; &lt;span style="color: #ffc66d"&gt;DataTable&lt;/span&gt; _table;

        &lt;span style="color: #cc7832"&gt;public&lt;/span&gt; DynamicDataTable(&lt;span style="color: #ffc66d"&gt;DataTable&lt;/span&gt; table) {
            _table = table;
        }
    }&lt;/pre&gt;

&lt;p&gt;For now, we’ll use a DataTable for the actual storage and a DynamicObject to provide an implementation of &lt;a href="http://msdn.microsoft.com/en-us/library/system.dynamic.idynamicmetaobjectprovider(VS.100).aspx"&gt;IDynamicMetaObjectProvider&lt;/a&gt;. What can we accomplish with this? Well, quite a lot, actually – in a very real sense, we’re only limited by our imagination.&lt;/p&gt;

&lt;h3&gt;GetMember&lt;/h3&gt;

&lt;p&gt;The first ability we want is to be able to extract a column out of the data table; given a DynamicDataTable “foo”, the expression “foo.Bar” should give us something enumerable that represents the data in the column. The DLR describes this operation as “get member”, and DLR-based languages implement a &lt;a href="http://msdn.microsoft.com/en-us/library/system.dynamic.getmemberbinder(VS.100).aspx"&gt;GetMemberBinder&lt;/a&gt; in order to bind a dynamic “get member” operation.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject(VS.100).aspx"&gt;DynamicObject&lt;/a&gt; makes it very easy for us to handle the GetMemberBinder. We simply override the virtual method TryGetMember and implement the behavior that we want. The binder has two properties: Name, which indicates the name of the member that is being bound, and IgnoreCase. You can reasonably expect that case-sensitive languages like C#, Ruby and Python will set IgnoreCase to false, while VB will set it to true.&lt;/p&gt;

&lt;pre style="font-family: consolas; background: black; color: white; font-size: 10pt; font-weight: bold"&gt;        &lt;span style="color: #cc7832"&gt;private&lt;/span&gt; &lt;span style="color: #ffc66d"&gt;DataColumn&lt;/span&gt; GetColumn(&lt;span style="color: #cc7832"&gt;string&lt;/span&gt; name, &lt;span style="color: #cc7832"&gt;bool&lt;/span&gt; ignoreCase) {
            &lt;span style="color: #cc7832"&gt;if&lt;/span&gt; (!ignoreCase) {
                &lt;span style="color: #cc7832"&gt;return&lt;/span&gt; _table.Columns[name];
            }
            &lt;span style="color: #cc7832"&gt;for&lt;/span&gt; (&lt;span style="color: #cc7832"&gt;int&lt;/span&gt; i = &lt;span style="color: #6897bb"&gt;0&lt;/span&gt;; i &amp;lt; _table.Columns.Count; i++) {
                &lt;span style="color: #cc7832"&gt;if&lt;/span&gt; (_table.Columns[i].ColumnName.Equals(name, &lt;span style="color: #ffc66d"&gt;StringComparison&lt;/span&gt;.InvariantCultureIgnoreCase)) {
                    &lt;span style="color: #cc7832"&gt;return&lt;/span&gt; _table.Columns[i];
                }
            }
            &lt;span style="color: #cc7832"&gt;return null&lt;/span&gt;;
        }

        &lt;span style="color: #cc7832"&gt;public override bool&lt;/span&gt; TryGetMember(&lt;span style="color: #ffc66d"&gt;GetMemberBinder&lt;/span&gt; binder, &lt;span style="color: #cc7832"&gt;out object&lt;/span&gt; result) {
            &lt;span style="color: #cc7832"&gt;var&lt;/span&gt; c = _table.Columns[binder.Name];
            &lt;span style="color: #cc7832"&gt;if&lt;/span&gt; (c == &lt;span style="color: #cc7832"&gt;null&lt;/span&gt;) {
                return &lt;span style="color: #cc7832"&gt;base&lt;/span&gt;.TryGetMember(binder, &lt;span style="color: #cc7832"&gt;out&lt;/span&gt; result);
            }
            &lt;span style="color: #cc7832"&gt;var&lt;/span&gt; a = &lt;span style="color: #ffc66d"&gt;Array&lt;/span&gt;.CreateInstance(c.DataType, _table.Rows.Count);
            &lt;span style="color: #cc7832"&gt;for&lt;/span&gt; (&lt;span style="color: #cc7832"&gt;int&lt;/span&gt; i = &lt;span style="color: #6897bb"&gt;0&lt;/span&gt;; i &amp;lt; _table.Rows.Count; i++) {
                a.SetValue(_table.Rows[i][c], i);
            }
            result = a;
            &lt;span style="color: #cc7832"&gt;return true&lt;/span&gt;;
        }&lt;/pre&gt;

&lt;p&gt;Here I’ve chosen to return an Array whose elements are typed identically to the column’s original data type. That’s because it’s very easy to create an Array of a particular type and to set its individual elements from the System.Objects that we can get from the DataRow.&lt;/p&gt;

&lt;p&gt;By factoring out GetColumn into a separate method, I’ve made it easy to change just this logic. We might want, for instance, to allow a symbol name like “hello_world” to match the column named “hello world”.&lt;/p&gt;

&lt;h3&gt;Non-dynamic members&lt;/h3&gt;

&lt;p&gt;What if I want to directly access other properties of the DataTable like the “Rows” DataRowCollection? The design of the DLR makes this easy. If you don’t handle a binding operation yourself, it’s possible to fall back to a default behavior implemented by the language-provided binder. And for VB, C#, Python and Ruby, the fallback behavior is to treat the object like a normal .NET object and to access its features via Reflection. That’s why it’s useful to call base.TryGetMember instead of throwing an exception when the column name can’t be found.&lt;/p&gt;

&lt;p&gt;So if we implement a trivial “Rows” property, a reference to DynamicDataTable.Rows will return DataTable.Rows even when the GetMember is performed dynamically at runtime (unless there actually &lt;strong&gt;is&lt;/strong&gt; a column named “Rows”…).&lt;/p&gt;

&lt;pre style="font-family: consolas; background: black; color: white; font-size: 10pt; font-weight: bold"&gt;        &lt;span style="color: #cc7832"&gt;public&lt;/span&gt; &lt;span style="color: #ffc66d"&gt;DataRowCollection&lt;/span&gt; Rows {
            &lt;span style="color: #cc7832"&gt;get&lt;/span&gt; { &lt;span style="color: #cc7832"&gt;return&lt;/span&gt; _table.Rows; }
        }&lt;/pre&gt;

&lt;h3&gt;SetMember&lt;/h3&gt;

&lt;p&gt;The next interesting thing we want to be able to do is to set a column on the DataTable whether or not it already exists. The DLR describes this operation as “set member”, and defines a corresponding &lt;a href="http://msdn.microsoft.com/en-us/library/system.dynamic.setmemberbinder(VS.100).aspx"&gt;SetMemberBinder&lt;/a&gt; to perform the binding operation. Like the GetMemberBinder, this class has two properties: Name and IgnoreCase.&lt;/p&gt;

&lt;p&gt;We want to be able to set the column either to a single repeated constant value or to a list of values. But there are lots of different lists we might like to support: for instance, lists, collections or even plain IEnumerables. Let’s make some decisions about the semantics of the SetMember operation on our type:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;If the object’s type implements IEnumerable and the object isn’t a System.String, then we’ll treat it like an enumeration. Otherwise, we’ll treat it like a single value. &lt;/li&gt;

  &lt;li&gt;If it’s an IEnumerable&amp;lt;T&amp;gt; we’ll use the generic type as our DataType. For a plain IEnumerable, the DataType will be System.Object. &lt;/li&gt;

  &lt;li&gt;If the object does not implement IEnumerable (or the object is a System.String) then the DataType will be the object’s actual RuntimeType. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For an enumeration, we’ll read items into a temporary array until we reach the number of rows in the table. If the enumeration ends before then, we’ll raise an error. If at that point, there are still additional items remaining in the enumeration, then we’ll also raise an error.&lt;/p&gt;

&lt;p&gt;The specific behavior of our implementation for each of these types isn’t very important. What is important is that we’ve identified all the types that we expect we might get, and have identified the logic we’re going to implement for those types. Now, on to the code!&lt;/p&gt;

&lt;pre style="font-family: consolas; background: black; color: white; font-size: 10pt; font-weight: bold"&gt;        &lt;span style="color: #cc7832"&gt;public override bool&lt;/span&gt; TrySetMember(&lt;span style="color: #ffc66d"&gt;SetMemberBinder&lt;/span&gt; binder, &lt;span style="color: #cc7832"&gt;object&lt;/span&gt; value) {
            &lt;span style="color: #ffc66d"&gt;Type&lt;/span&gt; dataType;
            &lt;span style="color: #ffc66d"&gt;IEnumerable&lt;/span&gt; values = (value &lt;span style="color: #cc7832"&gt;is string&lt;/span&gt;) ? &lt;span style="color: #cc7832"&gt;null&lt;/span&gt; : (value &lt;span style="color: #cc7832"&gt;as&lt;/span&gt; &lt;span style="color: #ffc66d"&gt;IEnumerable&lt;/span&gt;);
            &lt;span style="color: #cc7832"&gt;bool&lt;/span&gt; rangeCheck = (values != &lt;span style="color: #cc7832"&gt;null&lt;/span&gt;);
            
            if (values != &lt;span style="color: #cc7832"&gt;null&lt;/span&gt;) {
                dataType = GetGenericTypeOfArityOne(value.GetType(), &lt;span style="color: #cc7832"&gt;typeof&lt;/span&gt;(&lt;span style="color: #ffc66d"&gt;IEnumerable&lt;/span&gt;&amp;lt;&amp;gt;)) ?? &lt;span style="color: #cc7832"&gt;typeof&lt;/span&gt;(&lt;span style="color: #cc7832"&gt;object&lt;/span&gt;);
            } &lt;span style="color: #cc7832"&gt;else&lt;/span&gt; {
                values = ConstantEnumerator(value);
                dataType = (value != &lt;span style="color: #cc7832"&gt;null&lt;/span&gt;) ? value.GetType() : &lt;span style="color: #cc7832"&gt;typeof&lt;/span&gt;(&lt;span style="color: #cc7832"&gt;object&lt;/span&gt;);
            }
            
            &lt;span style="color: #cc7832"&gt;object&lt;/span&gt;[] data = &lt;span style="color: #cc7832"&gt;new object&lt;/span&gt;[_table.Rows.Count];
            &lt;span style="color: #cc7832"&gt;var&lt;/span&gt; nc = values.GetEnumerator();
            &lt;span style="color: #cc7832"&gt;int&lt;/span&gt; rc = _table.Rows.Count;
            &lt;span style="color: #cc7832"&gt;for&lt;/span&gt; (&lt;span style="color: #cc7832"&gt;int&lt;/span&gt; i = &lt;span style="color: #6897bb"&gt;0&lt;/span&gt;; i &amp;lt; rc; i++) {
                if (!nc.MoveNext()) {
                    &lt;span style="color: #cc7832"&gt;throw new&lt;/span&gt; &lt;span style="color: #ffc66d"&gt;ArgumentException&lt;/span&gt;(&lt;span style="color: #ffc66d"&gt;String&lt;/span&gt;.Format(&lt;span style="color: #a5c25c"&gt;&amp;quot;Only {0} values found ({1} needed)&amp;quot;&lt;/span&gt;, i, rc));
                }
                data[i] = nc.Current;
            }
            &lt;span style="color: #cc7832"&gt;if&lt;/span&gt; (rangeCheck &amp;amp;&amp;amp; nc.MoveNext()) {
                &lt;span style="color: #cc7832"&gt;throw new&lt;/span&gt; &lt;span style="color: #ffc66d"&gt;ArgumentException&lt;/span&gt;(&lt;span style="color: #ffc66d"&gt;String&lt;/span&gt;.Format(&lt;span style="color: #a5c25c"&gt;&amp;quot;More than {0} values found&amp;quot;&lt;/span&gt;, rc));
            }
            
            &lt;span style="color: #cc7832"&gt;var&lt;/span&gt; c = GetColumn(binder.Name, binder.IgnoreCase);
            &lt;span style="color: #cc7832"&gt;if&lt;/span&gt; (c != &lt;span style="color: #cc7832"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; c.DataType != dataType) {
                _table.Columns.Remove(c);
                c = &lt;span style="color: #cc7832"&gt;null&lt;/span&gt;;
            }
            &lt;span style="color: #cc7832"&gt;if&lt;/span&gt; (c == &lt;span style="color: #cc7832"&gt;null&lt;/span&gt;) {
                c = _table.Columns.Add(binder.Name, dataType);
            }
            
            &lt;span style="color: #cc7832"&gt;for&lt;/span&gt; (&lt;span style="color: #cc7832"&gt;int&lt;/span&gt; i = &lt;span style="color: #6897bb"&gt;0&lt;/span&gt;; i &amp;lt; rc; i++) {
                _table.Rows[i][c] = data[i];
            }
            &lt;span style="color: #cc7832"&gt;return true&lt;/span&gt;;
        }&lt;/pre&gt;

&lt;p&gt;(GetGenericTypeOfArityOne and ConstantEnumerator are methods whose names are pretty self-explanatory – and whose implementations can be found in the downloadable source code).&lt;/p&gt;

&lt;p&gt;Armed with these two methods, our type now supports all of the operations we need to implement the sample program described in Part 0 of this series. A version of the complete source code can be downloaded &lt;a href="http://www.hagenlocher.org/software/DynamicDataObject.1.zip"&gt;this location&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In Part 2, we’ll add the ability to perform numerical operations between columns. See you then!&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9638337" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/curth/archive/tags/DynamicDataTable/default.aspx">DynamicDataTable</category></item><item><title>DynamicDataTable, Part 0</title><link>http://blogs.msdn.com/curth/archive/2009/05/21/dynamicdatatable-part-0.aspx</link><pubDate>Fri, 22 May 2009 08:01:57 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9634704</guid><dc:creator>curth</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/curth/comments/9634704.aspx</comments><wfw:commentRss>http://blogs.msdn.com/curth/commentrss.aspx?PostID=9634704</wfw:commentRss><description>&lt;p&gt;To commemorate the &lt;a href="http://blogs.msdn.com/jasonz/archive/2009/05/20/general-download-of-vs2010-net-framework-4-0-beta-1.aspx"&gt;first beta release&lt;/a&gt; of the first CLR to contain the DLR, I’m going to try to implement something more interesting than useful – a dynamic version of the &lt;a href="http://msdn.microsoft.com/en-us/library/system.data.datatable.aspx"&gt;DataTable&lt;/a&gt; class. My goal is to show how the dynamic support in C#4 and VB10 can be used to create a better development experience, and to show how you can work effectively with &lt;a href="http://msdn.microsoft.com/en-us/library/system.dynamic.idynamicmetaobjectprovider(VS.100).aspx"&gt;IDynamicMetaObjectProvider&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;The BCL’s DataTable is already fairly dynamic; its columns can vary at runtime in type and name. You can even add and remove columns on-the-fly. As such, it’s a pretty good candidate for “dynamicizing”. Of course, we can’t actually modify the existing DataTable implementation, so I’ll start out by creating a wrapper for it using &lt;a href="http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject(VS.100).aspx"&gt;DynamicObject&lt;/a&gt;. Where I hope to end up is with a self-contained implementation that implements its own &lt;a href="http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicmetaobject(VS.100).aspx"&gt;DynamicMetaObject&lt;/a&gt; rather than leaning on DynamicObject and DataTable.&lt;/p&gt;  &lt;p&gt;Here’s a sneak preview of Part 1:&lt;/p&gt;  &lt;pre style="font-family: consolas; background: black; color: white; font-size: 10pt; font-weight: bold"&gt;    &lt;span style="color: #cc7832"&gt;public static class&lt;/span&gt; &lt;span style="color: #ffc66d"&gt;Program&lt;/span&gt; {
        &lt;span style="color: #cc7832"&gt;private static&lt;/span&gt; &lt;span style="color: #ffc66d"&gt;DataTable&lt;/span&gt; CreateTable() {
            &lt;span style="color: #ffc66d"&gt;DataTable&lt;/span&gt; table = &lt;span style="color: #cc7832"&gt;new&lt;/span&gt; &lt;span style="color: #ffc66d"&gt;DataTable&lt;/span&gt;();
            table.Columns.Add(&lt;span style="color: #a5c25c"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;, &lt;span style="color: #cc7832"&gt;typeof&lt;/span&gt;(&lt;span style="color: #cc7832"&gt;string&lt;/span&gt;));
            table.Columns.Add(&lt;span style="color: #a5c25c"&gt;&amp;quot;Value&amp;quot;&lt;/span&gt;, &lt;span style="color: #cc7832"&gt;typeof&lt;/span&gt;(&lt;span style="color: #cc7832"&gt;int&lt;/span&gt;));

            table.Rows.Add(&lt;span style="color: #a5c25c"&gt;&amp;quot;Bob&amp;quot;&lt;/span&gt;, &lt;span style="color: #6897bb"&gt;23&lt;/span&gt;);
            table.Rows.Add(&lt;span style="color: #a5c25c"&gt;&amp;quot;Karen&amp;quot;&lt;/span&gt;, &lt;span style="color: #6897bb"&gt;17&lt;/span&gt;);
            table.Rows.Add(&lt;span style="color: #a5c25c"&gt;&amp;quot;Allen&amp;quot;&lt;/span&gt;, &lt;span style="color: #6897bb"&gt;10&lt;/span&gt;);
            table.Rows.Add(&lt;span style="color: #a5c25c"&gt;&amp;quot;Grace&amp;quot;&lt;/span&gt;, &lt;span style="color: #6897bb"&gt;31&lt;/span&gt;);
            &lt;span style="color: #cc7832"&gt;return&lt;/span&gt; table;
        }
        &lt;span style="color: #cc7832"&gt;public static void&lt;/span&gt; Main(&lt;span style="color: #cc7832"&gt;string&lt;/span&gt;[] args) {
            &lt;span style="color: #ffc66d"&gt;DataTable&lt;/span&gt; table = CreateTable();
            &lt;span style="color: #cc7832"&gt;dynamic&lt;/span&gt; t = &lt;span style="color: #cc7832"&gt;new&lt;/span&gt; &lt;span style="color: #ffc66d"&gt;DynamicDataTable&lt;/span&gt;(table);
            t.NewName = t.Name;
            t.Name = &lt;span style="color: #a5c25c"&gt;&amp;quot;unknown&amp;quot;&lt;/span&gt;;
            &lt;span style="color: #cc7832"&gt;foreach&lt;/span&gt; (&lt;span style="color: #cc7832"&gt;var&lt;/span&gt; r &lt;span style="color: #cc7832"&gt;in&lt;/span&gt; t.NewName) {
                System.&lt;span style="color: #ffc66d"&gt;Console&lt;/span&gt;.WriteLine(r);
            }
        }
    }&lt;/pre&gt;

&lt;p&gt;See you again soon!&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9634704" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/curth/archive/tags/DynamicDataTable/default.aspx">DynamicDataTable</category></item></channel></rss>