This morning I just played around with the new C# 4.0 dynamic feature. Using the dynamic keyword allows you to bind to properties, indexers and methods during runtime. This means that during compile time there is no check if the methods, properties or whatever you are calling are really existent, you experience any missing pieces during runtime.
On the other hand this allows you to implement some flexible stuff. You can implement your own dynamic objects just deriving from DynamicObject and overriding the methods you are interested in.
So, I just implemented a short demo how to use DynamicObject derived classes to wrap some parts of System.Data.SqlClient to access data from tables directly, without any code gen.
The result is, that I can write the following code and it will resolve during runtime if it can find data for the specified tables.
using( dynamic db = new DirectDataAccess("connectionstring") ){ Console.WriteLine( db.Products.Count ); Console.WriteLine( db.Customers[15].CompanyName ); Console.WriteLine( db.Employees.Row10.LastName );}
Here is how it works. First lets have a look at the responsible classes:
DirectDataAccess, DirectRowAccess and DirectColumnAccess are deriving from DynamicObject. My approach is simple and just for demo purposes. Also it just enables read access and does not handle errors well. I encapsulate DataTable as member and create new instances of DirectRowAccess and DirectColumnAccess through the overriden TryGetMember methods.
Lets have a look into the DirectDataAccess implementation:
public class DirectDataAccess : DynamicObject, IDisposable{ SqlConnection connection = null; public DirectDataAccess(string connectionString) { connection = new SqlConnection(connectionString); connection.Open(); } public void Dispose() { /// removed for clarity } public override bool TryGetMember(GetMemberBinder binder, out object result) { DataTable table = new DataTable(binder.Name); SqlCommand cmd = new SqlCommand(); cmd.CommandText = "SELECT * FROM " + binder.Name; cmd.CommandType = CommandType.Text; cmd.Connection = connection; try { table.Load(cmd.ExecuteReader()); } catch (Exception) { result = null; return false; } result = new DirectRowAccess(table); return true; }}
// db is an instance of DirectDataAccessvar table = db.Products;
public class DirectRowAccess : DynamicObject{ private DataTable table = null; public DirectRowAccess(DataTable table) { this.table = table; } public override bool TryGetMember(GetMemberBinder binder, out object result) { string raw = binder.Name.Substring(3, binder.Name.Length - 3); int index = Convert.ToInt32(raw); try { result = new DirectColumnAccess(table.Rows[index]); return true; } catch (Exception) { result = null; return false; } } public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) { result = new DirectColumnAccess( table.Rows[(int)indexes[0]]); return true; } public int Count { get { return table.Rows.Count; } }}
var row = db.Customers[10];
var row = db.Customers.Row10;
public class DirectColumnAccess : DynamicObject{ private DataRow row = null; public DirectColumnAccess(DataRow row) { this.row = row; } public override bool TryGetMember(GetMemberBinder binder, out object result) { try { result = row[binder.Name]; return true; } catch (Exception) { result = null; return false; } } public override string ToString() { return string.Join(",", row.ItemArray); }}
var companyName = db.Customers[10].CompanyName;
Console.WriteLine( db.Customers[10] );
This is just demo code, written just for fun!
Another Idea I had was to write a generic REST object which implements the common HTTP Verbs GET, POST, PUT and DELTE to talk to REST Services. I thought on writing something like this:
dynamic rest = new REST("http://twitter.com")var xml = rest.GET.statuses_public__timeline.AsXml();var postXml = ...;var xml2 = rest.POST.statuses_update(postXml).AsXml();
But there are some problems to solve like the fact that you can’t use a forward slash in a method or property name and masking the underscore is maybe not a good idea.
What do you think, are there any usages in your environment where DynamicObject derived implemenations could help?