Background
I’m working with Microsoft Dynamics CRM 2011 QueryExpressions, which for all you non-CRM people out there, just know that I’m working with an SDK to access a database that requires you to put the string names of the columns you are selecting in a custom ColumnSet class:
new ColumnSet("personid", "name", "age");
The SDK does generate early bound classes so I do have classes for all the database tables, and the early bound classes all have a dictionary whose key are the columns of the table that have been populated on the object. ie:
var p = new Person { Name = "John", Age = 39, SSN = null };
p.Attributes.Count == 3;
// p.Attributes.Keys == { "name", "age", "ssn" };
The Problem
I have three issues when populating the ColumnSet
- I forget what columns a class/table contains
- I fat finger some of the columns and don’t get an error until runtime
- The column Names all have to be lower case when instantiating the ColumnSet, which makes for poor readability ie
thissillyexampleisntthatreadablevsThisSillyExampleIsntThatReadable
All three of these issues can be solved by early binding.
I know I can create an enum or stuct for each class that contains all of a class’s columns ie: new ColumnSet(PersonColumns.PersonId, PersonColumns.Name, PersonColumns.Age), but I want it to use the classes that have already been generated.
My Best Attempt
The best that I can currently come up with is this:
ColumnSetFactory.Create<Person>(p => p.PersonId = null, p.Name = null, p.Age = null);
Where Create accepts an object of type T (person in this example) and then inspects the dictionary of the object to generate and return the ColumnSet.
The Goal
Have a generic function that utilizes the early bound classes to generate the ColumnSet:
ColumnSetFactory.Create<Person>(p => p.PersonId, p.Name, p.Age);
Any ideas?
Your attempt/goal syntax does not work in C# unfortunately, but you could probably get something close to it.
I’m not familiar with the dynamics crm so I’m making this assumption, the constructor for
ColumnSettakes a variable amount of string arguments and has a signature:You could create a lambda expression that returns an object initializer (to create an anonymous object) and use some reflection to invoke the constructor using the initializer’s member bindings. If I understand what you are trying to accomplish, you want to use existing parameter names of an object to essentially pass those names to this constructor to create the object.
Here’s how you can do that:
Then to use it, call it like this:
Which would generate an equivalent call to the constructor:
You could even make up column names and give them random values, the values themselves will not be used, just the name of the member.
Which would generate an equivalent call to the constructor: