# Wednesday, February 20, 2008
So a few weeks back there was a post on the Genome TeamBlog which included a link to one of my lambda abuse posts from last year.

At any rate - the problem they faced was that with code like this:

DataContext Context = new DataContext();

string connStr = "";

 

DataDomainSchema schema = DataDomainSchema.LoadFrom("SomeMappingFile");

schema.CreateDbSchema(connStr);

 

DataDomain dd = new DataDomain(schema, connStr);

 

using (Context.Push(ShortRunningTransactionContext.Create()))

{

    Customer tt = dd.New<Customer>();

    tt.Name = "TechTalk";

 

    RootProject tt_hk = dd.New<RootProject>();

    tt_hk.Name = "Housekeeping";

 

    ChildProject tt_hk_hol = dd.New<ChildProject>();

    tt_hk_hol.Name = "Holiday";

    tt_hk.ChildProjects.Add(tt_hk_hol);

 

    ChildProject tt_hk_ill = dd.New<ChildProject>();

    tt_hk_ill.Name = "Illness";

 

    tt_hk.ChildProjects.Add(tt_hk_ill);

 

    tt.RootProjects.Add(tt_hk);

 

    RootProject tt_g = dd.New<RootProject>();

    tt_g.Name = "Genome";

 

    ChildProject tt_g_dev = dd.New<ChildProject>();

    tt_g_dev.Name = "Development";

    tt_g.ChildProjects.Add(tt_g_dev);

 

    ChildProject tt_g_mnt = dd.New<ChildProject>();

    tt_g_mnt.Name = "Maintenance";

    tt_g.ChildProjects.Add(tt_g_mnt);

    tt.RootProjects.Add(tt_g);

 

    Context.CommitCurrent();

}


You ended up with a very flat member initialization structure plagued with:
  • Having to explicitly name child instances being added to collections - there's a lot of unnecessary noise.
  • Where you can't easily see the structure i.e. it's not visually hierarchical, so at a glance you're not sure just what the structure is compared to say looking at an xml document with nested elements where it's quite obvious.
At any rate, the guys at the Genome project attempted to overcome this using the nested lambdas (what I coined a "DSL" at the time, though It's a terrible and inaccurate term for what's effectively just a bit of a "trick" relying on side effects of evaluation) - it didn't go so well though because of course at first glance the syntax look strongly typed, the reality is it's anything but, and refactoring tools just aren't going to do things like renaming of keys in the hash style syntax i.e. key => value, because the key is just a Lambda parameter.

But all is not lost - of course with C# 3.0 we already have a great syntax for doing this kind of hierarchical initialization, say for this set of types:

public class BlogPost

{

    private readonly List<string> _tags = new List<string>();

    private readonly BlogUser _createdBy = new BlogUser();       

 

    public string Title { get; set; }

 

    public string Body { get; set; }

 

    public List<string> Tags

    {

        get { return _tags; }

    }

 

    public BlogUser CreatedBy

    {

        get { return _createdBy; }

    }

 

    public BlogUser LastEditedBy { get; set; }

}

 

public class BlogUser

{

    public int Age { get; set; }

    public string Name { get; set; }

}


We could do something like this to initialize an instance of BlogPost:

BlogPost post = new BlogPost()

{

    Title = "Post on Lambdas",

    Body = "This is a post...",

    Tags =

    {

        ".Net",

        "Lambda",

        "C#3.0"

    },

    CreatedBy =

    {

        Name = "Jane Doe",

        Age = 35

    },

    LastEditedBy = new BlogUser()

    {

        Name = "Joe Bloggs",

        Age = 25

    }

};


But the catch for the Genome guys is that it looks like they need to construct their entities using their DataDomain class ...  I don't know about how there product works but I can only assume it's either to get a transparent proxy for change tracking purposes or to enlist it into the current session etc. (though if it's just to enlist the entity I can't see why they need to bother with getting the DataDomain to create a new instance, surely they could manually enlist it).

At any rate that's irrelevant :)

So I got to thinking that of course member initialization is one of the Lambda-friendly things we can do because it's expressed in a single statement - so we can happily take the above code snippet and express it like so:

BlogPost post = evaluator.Create(() => new BlogPost()

{

    Title = "Post on Lambdas",

    Body = "This is a post...",

    Tags =

    {

        ".Net",

        "Lambda",

        "C#3.0"

    },

    CreatedBy =

    {

        Name = "Jane Doe",

        Age = 35

    },

    LastEditedBy = new BlogUser()

    {                   

        Name = "Joe Bloggs",

        Age = 25

    }

});


Where evaluator is an instance of a class I wrote called ServiceInjectionEvaluator ... the Create method (as you can probably guess) has the following signature:


  public
T Create<T>(Expression<Func<T>> expression)


The service injection evaluator just relies on being configured with an IServiceProvider capable of resolving instances of types... at this point we just unwind the expression, substituting our own instance activation mechanism wherever we stumble upon a NewExpression and walking through the expressions executing each bit as required - though it makes the assumption that you're going to have either a New or MemberInit expression at the top level of the Lambda, otherwise we just compile the whole thing and throw it back without any changes (because I don't want to bother writing code to visit the other types of expression node).

public class ServiceInjectionEvaluator

{

    private readonly IServiceProvider _serviceProvider;

 

    public ServiceInjectionEvaluator(IServiceProvider serviceProvider)

    {

        _serviceProvider = serviceProvider;

    }

 

    public T Create<T>(Expression<Func<T>> expression)

    {

        switch (expression.Body.NodeType)

        {

            case ExpressionType.New:

            case ExpressionType.MemberInit:

                return (T)EvaluateExpression(expression.Body);

            default:

                return expression.Compile().Invoke();

        }

    }

 

    private object GetInstanceWithInit(MemberInitExpression expression)

    {

        object instance = GetInstance(expression.NewExpression);

        foreach (MemberBinding binding in expression.Bindings)

        {

            ApplyBinding(instance, binding);

        }

        return instance;

    }

 

    private void ApplyBinding(object instance, MemberBinding binding)

    {           

        switch (binding.BindingType)

        {                   

            case MemberBindingType.Assignment:

                ApplyAssignmentBinding(instance, (MemberAssignment)binding);

                break;

            case MemberBindingType.ListBinding:

                ApplyListBinding(instance, (MemberListBinding)binding);

                break;

            case MemberBindingType.MemberBinding:

                ApplyMemberBinding(instance, (MemberMemberBinding)binding);

                break;

            default:

                throw new NotImplementedException();

        }

    }

 

    private void ApplyMemberBinding(object instance, MemberMemberBinding binding)

    {

        PropertyInfo property = (PropertyInfo)binding.Member;

        object memberValue = property.GetValue(instance, null);

        foreach (MemberBinding childBinding in binding.Bindings)

        {

            ApplyBinding(memberValue, childBinding);

        }

    }

 

    private void ApplyListBinding(object instance, MemberListBinding binding)

    {

        object list = ((PropertyInfo)binding.Member).GetValue(instance, null);

 

        foreach (ElementInit elementInit in binding.Initializers)

        {

            Delegate compiled = Expression.Lambda(Expression.NewArrayInit(typeof(object), elementInit.Arguments.ToArray())).Compile();

            object[] arguments = (object[])compiled.DynamicInvoke();

            elementInit.AddMethod.Invoke(list, arguments);

        }

    }

 

    private void ApplyAssignmentBinding(object instance, MemberAssignment assignment)

    {

        object value = EvaluateExpression(assignment.Expression);

 

        PropertyInfo info = (PropertyInfo)assignment.Member;

        info.SetValue(instance, value, null);

    }

 

    private object EvaluateExpression(Expression expression)

    {

        switch (expression.NodeType)

        {

            case ExpressionType.New:

                return GetInstance((NewExpression) expression);

            case ExpressionType.MemberInit:

                return GetInstanceWithInit((MemberInitExpression) expression);

            default:

                return Expression.Lambda(expression).Compile().DynamicInvoke();

        }

    }

 

    private object GetInstance(NewExpression expression)

    {

        return _serviceProvider.GetService(expression.Type);

    }

}


The only thing left is to then either provide an existing instance of IServiceProvider (i.e. the Windsor container) or creating an adaptor

public class DataDomainServiceProvider : IServiceProvider

{

    private readonly DataDomain _domain;

    private static readonly MethodInfo member = typeof(DataDomain).GetMethod("New");

 

    public DataDomainServiceProvider(DataDomain domain)

    {

        _domain = domain;

    }

 

    public object GetService(Type serviceType)

    {           

        return member.MakeGenericMethod(serviceType).Invoke(_domain, null);           

    }

}


There's a few things the enterprising mind can do with substitutions and member initialization I can think of, especially around IoC - anyone else have some ideas or thoughts on using/abusing them?

.Net | C# 3.0 | LINQ
posted @ Wednesday, February 20, 2008 2:01:38 PM (New Zealand Daylight Time, UTC+13:00)    Comments [0] | |
# Thursday, July 05, 2007

So I see both Andrew, Nick and Alex J have some thoughts on languages, and of course Rowans post sparked it off... and people talk about beautiful languages, mentioning expressiveness in the same breath. 

Personally I love how expressive Ruby is - I think potentially because I got my first exposure to ruby after reading Why's poignant guide a while back (I see there are new chapters ...oooh) which was quite surreal compared to how I say learnt C++ (from reading the Borland Turbo C++ manual when I was 11, also my first exposure to OOP)...

When I code in ruby I feel like I'm telling stories... I dig that :)

So Alex J mentioned that extension methods let us achieve much of the syntactic sugar that ruby provides (though obviously in ruby's case this isn't so much syntactic sugar as core mechanisms in the language itself) - and of course Lambda expressions are helping too, but does expressive == good 100% of the time?   I don't think I'm qualified to say, but I can't help but feel that a language which is very expressive, isn't necessarily the easiest to manipulate and refactor, so I may not be as productive and it may not feel as fluent to me... I quite liked this resharper horizons post which suggests that tooling support should probably influence future language design - could that requirement possibly fight against an increased level of expressiveness in a language, will compromises need to made, or is nirvana just around the corner?

As for C# vs VB.Net - large clumsy keywords are only a probablem until something like Resharper steps in... when I'm developing I see a lot of unusued space on the right hand side of the editor with C#... if VB.Net fills it up, and I'm not typing any harder to get there, why should I care - hell it'll probably make a VB.Net Resharper Jedi look more impressive then the C# equivalent, he'll be producing more characters ;o)

OK, well I figured this post should at least have some code... I'd feel uneasy otherwise... so how about:

public static class CommonExtensions
{
    public static Action<Action<int>> LoopTo(this int start, int end)
    {
        return new Action<Action<int>>(action => To(start, end).ForEach(i => action(i)));
    }
 
    public static IEnumerable<int> To(this int start, int end)
    {
        if (end < start)
            for (int i = start; i > end - 1; i--)
                yield return i;
        else
            for (int i = start; i < end + 1; i++)
                yield return i;   
    }
 
    public static void ForEach<T>(this IEnumerable<T> sequence, Action<T> action)
    {
        foreach (T item in sequence) action(item);
    }
 
    public static void PrintLine(this object o)
    {
        Console.WriteLine(o);
    }
}


So now we could try and do this....

// ruby
(10..20).each { |i| puts i }

// C#
10.LoopTo(20) ( i => i.PrintLine() );


Alas I don't think C# will ever match ruby in this game, no matter how we try to nudge it there... and until the development community figures out where the healthy place is to draw the line in the attempt, we may be doing more harm then good by pushing for it, sacrificing discoverability/maintainability for expressiveness.   Maybe that's just dogma, and expressiveness makes code inherently easier to maintain in the first place, so we don't need to care.... time will tell.

Of course I could be wrong, I am a little sleepy ;o)
posted @ Thursday, July 05, 2007 12:03:27 AM (New Zealand Standard Time, UTC+12:00)    Comments [0] | |
# Tuesday, July 03, 2007

So I've tidied up the source for the DSL from my last post a little... though my "test" was to represent a DSL similar to the one Ayende displayed in Brail - I haven't implemented any monorail view engine integration, there's little point I feel, I was more interested in being able to display a nested DSL-like syntax, and parse the necessary information out of it as required. 

You can grab it from SVN repository here (edit: I've now fix the PROPFIND proxy issue, so the link should work)

At any rate, probably the most interesting example is the one that takes this code:

var people = new List<Person>()
{
    new Person() { FirstName = "Alex", LastName = "Henderson"},
    new Person() { FirstName = "Joe", LastName = "Bloggs"}
};
 
var compDsl = new ComponentDsl();
 
compDsl.Add
(
    GridComponent => compDsl.Component
    (
        compDsl.Parameters
        (
            source => people
        ),
        header => compDsl.Section
        (
            tr => compDsl.As
            (
                th => compDsl.As
                (
                    compDsl.Text("Names")
                )
            )
        ),
        item => compDsl.Section
        (
            tr => compDsl.As
            (
                td => compDsl.As
                (
                    compDsl.Item<Person>(p => p.FirstName + " " + p.LastName)
                )
            )
        )
    )
);
 
var dsl = new StandardDsl();
 
dsl.Add
(
    html => dsl.As
    (
        body => compDsl
    )
);

And converts it to this xhtml...

<html>
  <body>
    <table>
      <tr>
        <th>Names</th>
      </tr>
      <tr>
        <td>Alex Henderson</td>
      </tr>
      <tr>
        <td>Joe Bloggs</td>
      </tr>
    </table>
  </body>
</html>

You can pretty quickly figure out what's going on by placing a breakpoint on the Execute() method of the StandardDsl class and tracing through all the calls - in essence all the nodes are emitted by calling the top-level Batch delegate which causes a recursive call down the "tree", with the information being emitted as a side-effect to an evaluation scope.

Though I used nodes - effectively creating a structure that's easier to parse, there's no reason why you couldn't make immediate calls to some kind of object, avoiding the need for a second round of parsing - the only trick is that you'd still need to use some kind of scoped stack to push/pop the names of the components because in a statement like this:

dsl.As
(
    GridComponent => dsl.Component
    (
      // etc. etc.
    )  
)


the call to dsl.Component needs some way to inspect the stack of names and pull "GridComponent" off the top.

I'd love to hear from anyone who could see a use for this kind of thing... it'd be nice to get a more realistic example... I'm struggling to think of anything practical myself.

[Edit: I Noticed the code formatting was pretty awful, so I've tidied it up a little... anyone got a good solution for copy/pasting code out of orcas (CopyAsHtml2005 doesn't appear to install under Orcas)]
.Net | C# 3.0 | DSL
posted @ Tuesday, July 03, 2007 11:01:26 PM (New Zealand Standard Time, UTC+12:00)    Comments [2] | |
# Friday, June 29, 2007

Following on from my posts on creating hashes (dictionaries) using lambdas (here, and here) and the little annotations "framework" I produced (here and here) which leverage the idea for annotating classes via extension methods... I've decided to turn my hand to creating a DSL using lambdas, on my continuing theme of C# 3.0 lambda abuse.

So first off... go have a look at Ayende's post DSL Support for brail ... that'll give you an idea of kinda what I'm trying to achieve.... so, here's an example of a simple DSL for building say a html table.

var dsl = new StandardDsl();

dsl.Add(
table => dsl.As(
  tr => dsl.As(
    td => dsl.Text(
"header1"
),
    td => dsl.Text(
"header2"
))));

Console
.WriteLine(DslToXml.ToXml(dsl));

which gives an output of:

<table><tr><td>header1</td><td>header2</td></tr></table>

Depending on taste you could lay it out differently, avoiding the mess of closing parentheses at the end of the Add call, say like:

var dsl = new StandardDsl();

dsl.Add
(
  table => dsl.As
  (
    tr => dsl.As
    (
      td => dsl.Text(
"header1"
),
      td => dsl.Text(
"header2"
)
    )
  )
);

Which is pretty easy on the eyes... now what about something a little more domain specific like the view component example Ayende gave for monorail... well here's my take on that, so say we have some people:

var people = new List<Person>()
{
 
new Person() { FirstName = "Alex", LastName = "Henderson"
},
 
new Person() { FirstName = "Joe", LastName = "Bloggs"
}
};

And we have a DSL specific to components...

var compDsl = new ComponentDsl();

compDsl.Add
(
  GridComponent => compDsl.As
  (
    compDsl.Component(source => people),
    header => compDsl.Section
    (
      tr => compDsl.As
      (
        th => compDsl.As
        (
          compDsl.Text(
"Names")
        )
      )
   
),
    item => compDsl.Section
    (
      tr => compDsl.As
      (
        td => compDsl.As
        (
          compDsl.Item<
Person>(p => p.FirstName + " "
+ p.LastName)
        )
      )
    )
  )
);

And now we could do this in-line with a bigger DSL for say a whole view, but we can also just reference them so I could do something like this to create the overall view:

var dsl = new StandardDsl();

dsl.Add
(
  html => dsl.As
  (
    body => compDsl
  )
);

Now once I've tidied the code up a bit I'll probably put it up for people to have a play with - I don't necessarily consider a "good idea" - but it's cute.  However for now let's have a quick look at how I'm doing it...

So to start with we have a delegate called "Batch" with the signature below - batch probably isn't the right name for this, I'm not really sure it matters all that much.

public delegate Batch[] Batch(Batch batch);

Batch takes a Batch and returns an array of Batch ;o) and to match that we then have say the "As" method on the DSL:

public Batch[] As(params Batch[] batches)
{
  Batch asBatch = new Batch(delegate(Batch
ignore)
  {
    ExecuteBatches(batches);
   
return null
;
  });
 
  IgnoreBatch(asBatch);

  return new Batch[] { asBatch };
}

Notice it takes one or more Batch instances, and returns a delegate which executes the batches, ignores the batch we just generated and returning the one Batch as an array... conforming to the expected return type of the Batch delegate.  Clear as mud? ;o)

Ignoring the batches actually just uses the annotation framework, so IgnoreBatch looks like this:

public void IgnoreBatch(Batch batch)
{
  batch.Annotate(Ignore =>
true
);
}

And then we check if a batch is ignored before processing it down the line by calling this method.

public bool IsBatchIgnored(Batch batch)
{
 
return batch.HasAnnotation("Ignore"
);
}

Last of all to actually "render" the DSL into some useful format we execute it (no Expression<>'s required, so it's very fast) ... which just call the top with null, which in turn calls the arguments, and those arguments arguments etc.  While doing that we write nodes (much like an Xml writer) against an "evaluation" scope, which associates a NodeWriter with the current thread.... basically the DSL ends up as a bunch of calls like:

NodeWriter writer = new NodeWriter();
writer.WriteStartNode(
new NamedNode("table"
))
  .WriteStartNode(
new NamedNode("tr"
))
    .WriteStartNode(
new NamedNode("td"
))
      .WriteNode(
new TextNode("column1"
))
    .WriteEndNode()
  .WriteEndNode()
.WriteEndNode();

where the nodes conform to this interface:

public interface INode
{
 
INode Parent { get; set
; }
 
List<INode> Nodes { get
; }
}


At which point it's trivial to walk the tree of INode's and do whatever you like with the information stored within it, and we can encapsulate new concepts by creating new types of node, which have payloads of additional information.

At any rate, next time I'll post a little more about how I'm doing it, and attach the code for people to have a play with.

.Net | C# 3.0 | DSL
posted @ Friday, June 29, 2007 10:12:23 PM (New Zealand Standard Time, UTC+12:00)    Comments [2] | |
# Thursday, June 14, 2007
Here's the code for my last post on Annotations - I tidied up a few things up (it's still very basic but it does work) there's a single test fixture to give you a guide for usage... so things like:

[Test]
public void QueryStoreForClassAnnotationsWithCertainKey()
{
   
ClassA target1 = new ClassA();
    ClassA target2 = new ClassA();
    ClassA target3 = new ClassA();

    target1.Annotate(Description =>
"class number 1");
    target2.Annotate(Description => "class number 2");
    target3.Annotate(Parsed =>
true);

    var results = AnnotationStore.Classes
      .Where(a => a.HasKey(
"Description"))
      .ToList();

    Assert
.AreEqual(2, results.Count);
}

And also the equivalent thing is possible for members... though I suspect annotating members isn't all that useful in most cases...

[Test]
public void QueryStoreForMemberAnnotations()
{
    ClassA target1 = new ClassA();
    ClassA target2 = new ClassA();
    ClassA target3 = new ClassA();

    target1.Annotate(() => target1.FirstName, CamelCase => true); // annotating a property
    target1.Annotate(() => target1.Field, Ignored => true); // annotating a field
    target2.Annotate(() => target2.Execute(), Parsed => true); // annotating a method

    target3.Annotate(Parsed =>
true);

    var results = AnnotationStore.Members
      .Where(p => p.HasKey(
"CamelCase"))
      .ToList();

    Assert.AreEqual(1, results.Count);
}


.Net | C# 3.0 | LINQ
posted @ Thursday, June 14, 2007 4:06:12 PM (New Zealand Standard Time, UTC+12:00)    Comments [1] | |

So I've been mulling some ideas over after the whole abusing lambdas for Hash table construction (here and here) ... and after reading a post on Jb Evain's blog I decided to create a little bit of code for doing annotations... so given a class say:

public class ClassA
{
    public int Id { get; set; }
    public string Name { get; set; }
}

You can then do this kind of thing (assuming you've added the apropriate namespace where the Annotations static class resides in)

[Test]
public void AnnotateClass()
{
    ClassA classA = new ClassA();
    classA.Annotate(IsValid =>
false);
    classA.Annotate(MapsToTable =>
"TblClassA", Key => "Id");
    classA.Annotate(Roles =>
new [] {"Administrator", "User"});

    Assert.IsFalse(classA.Annotation<bool>("IsValid"));
    Assert.AreEqual("TblClassA", classA.Annotation<string>("MapsToTable"));
    Assert.AreEqual("Id", classA.Annotation<string>("Key"));
}

Or, perhaps you want to attach some annotations to a specific property... no problem!

[Test]
public void AnnotateProperty()
{
    ClassA classA = new ClassA();
    classA.Annotate(() => classA.Name, CanBeNull =>
true);
    bool canBeNull = classA.Annotation<bool>(() => classA.Name, "CanBeNull");
    Assert.AreEqual(true, canBeNull);
}

Under the hood the values are stored against a dictionary where the keys (in this case the instance of classA) are weak referenced... so once classA is garbage collected the entries in the dictionary will also dissapear in time (next time any method touches the dictionary).

The nice thing is obviously you can directly interogate the Annotations static class itself with a query expression to say find all objects with a certain annotation.

.Net | C# 3.0 | LINQ
posted @ Thursday, June 14, 2007 10:32:16 AM (New Zealand Standard Time, UTC+12:00)    Comments [2] | |
# Tuesday, June 12, 2007

So, I got a comment on the last post about hashes from lambdas (from Andrey Shchekin)... It pointed out the fact that you don't need to use expressions at all... which hilights an observation that I hadn't made myself - such that the lambda parameter names are available in the generated delegate... which of course makes perfect sense!

So given:

Func<string, T> func = Name => "Value";

You can get the lambda parameter "Name" from the function delegate by calling:

func.Method.GetParameters()[0].Name (would return "Name")

Here's the revised Hash method from Andrey:

public Dictionary<string, T> Hash<T>(params Func<string, T>[] args)
where T : class
{
   
var items = new Dictionary<string, T>();
   
foreach (var func in args)
    {
       
var item = func(null);
        items.Add(func.Method.GetParameters()[0].Name, item);
    }
   
return items;
}

very elegant and simple :)

He even did some stats, which I suspect are probably a lot more accurate then my inital observations:

For 10000 consecutive calls:

WithAdd 10.0144ms
WithLambdas 9713.968ms
WithLambdasConstantsOnly 240.3456ms
WithDelegates 30.0432ms

Now what about multiple parameters... so far I can't think of any uses I would have for it... perhaps a 2 level configuration dictionary?

[Test]
public void HashTwoLevelDict()
{
   
Dictionary<string, Dictionary<string, object>> config = this.Hash<object>(
     (Connection, DriverClass) =>
typeof(SqlClientDriver),
     (Dialect, DialectClass) =>
typeof(MsSql2000Dialect),
     (Connection, Provider) =>
typeof(DriverConnectionProvider),
     (Connection, ConnectionString) =>
"Data Source=.;Initial Catalog=test;Integrated Security=SSPI");

    Assert.AreEqual(typeof(SqlClientDriver), config["Connection"]["DriverClass"]);
}

Who knows... I look forward to seeing how Lambdas get used and abused for non-functional programming tasks :)
.Net | C# 3.0 | LINQ
posted @ Tuesday, June 12, 2007 1:22:21 PM (New Zealand Standard Time, UTC+12:00)    Comments [0] | |
# Monday, June 11, 2007
So first off... I'm surely not the first person to see the resemblance between a lambda expression and a hash table declaration in Ruby... so I had a go at populating a dictionary using lambda's... so given this:

[Test]
public void Evaluate()
{
    Dictionary<string, string> items = Hash(Name => "alex", Age => "10", Height => "20");
    Assert.AreEqual("alex", items["Name"]);
    Assert.AreEqual("10", items["Age"]);
    Assert.AreEqual("20", items["Height"]);
}

I got my desired result pretty quickly...

public Dictionary<string, T> Hash<T>(params Expression<Func<string, T>>[] args)
where T: class
{
    Dictionary<string, T> items = new Dictionary<string, T>();
    foreach (Expression<Func<string, T>> expression in args)
    {
       ConstantExpression itemValueExpression = expression.Body as ConstantExpression;
       if (itemValueExpression == null
       throw new InvalidCastException("The body of the expression must be of type ConstantExpression");
        T item = itemValueExpression.Value
as T;
        items.Add(expression.Parameters[0].Name, item);
    }
    return items;
}

But, then I tried this...

[Test]
public void EvaluateForObjects()
{
   
Dictionary<string, object> items = Hash<object>(Name => "alex", TargetType => typeof(Uri), Id => 10);
   
Assert.AreEqual(10, items["Id"]);
}

Which fails, the last key/value pair (Id => 10) isn't represented as a ConstantExpression, so to support it (and other eventualities) I modified my code a smidge...

public Dictionary<string, T> Hash<T>(params Expression<Func<string, T>>[] args)
where T: class
{
   
Dictionary<string, T> items = new Dictionary<string, T>();
   
foreach (Expression<Func<string, T>> expression in args)
   
{
       
ConstantExpression constantExpression = expression.Body as ConstantExpression;
        T item =
null;
       
if (constantExpression != null)
        {
          item = constantExpression.Value
as T;
        }
       
else
       
{
           
item = Expression.Lambda<Func<T>>(expression.Body).Compile()();
       
}
        items.Add(expression.Parameters[0].Name, item);
    }
    return items;
}

Now... let's compare performance to say, adding the values using the Add method... so... for a million consecutive executions (in milliseconds) a quick test yielded these results...

Execution # Using 'Hash' Using Dictionary.Add()
1 9718 1268
2 9588 1310
3 9636 1494

Which I suspect tells me nothing more then the fact that the "Hash" style initialization is a lot slower, but not slow enough to completely discourage me.


Edit: There seems to be a bit of interest in this lately, so don't forget to take a look at the other related posts if you found this interesting.

.Net | C# 3.0 | LINQ
posted @ Monday, June 11, 2007 9:32:15 PM (New Zealand Standard Time, UTC+12:00)    Comments [2] | |
# Tuesday, March 06, 2007
Have you ever wanted to be able to do something like this in C#?

string propertyName = GetName(MyClass.MyProperty);

Well I have, in fact I've wanted the ability to do this since Version 1 of the .Net Framework, and now with C# 3.0 we finally can!

First off, check out the original blog post here - Symbols in C# 3.0 by Jafar Husain - it's a clever (and once I thought about, plainly obvious) use of extension methods and expression trees.

public static class SymbolExtensions

{

    public static string GetPropertySymbol<T,R>(this T obj, Expression<Func<T, R>> expr)

    {

        return ((System.Linq.Expressions.MemberExpression)

           (((System.Linq.Expressions.LambdaExpression)(expr)).Body)).Member.Name;

    }

}


Usage requires a lambda, but that's not to painful, here's example usage:

MyClass o;

//...

string propertyName = this.GetPropertySymbol(o => o.MyProperty)


The beauty of this is that refactoring is entirely painless, you don't need to spend time reviewing all the optional string replacements that resharper may have found in case you haven't mirrored a property or method name change correctly... it also looks like it could offer some nice usability improvements to some unit testing scenarios (nothing worse then unit tests that don't seamlessly refactor with your code).

I wonder what other ideas are floating around for expression trees at the moment (outside of the obvious querying concepts) ?

posted @ Tuesday, March 06, 2007 3:18:22 PM (New Zealand Daylight Time, UTC+13:00)    Comments [0] | |
Search
FeedCount

Tags...
.Net (83) .Net Reactor (4) .net user groups (9) 2008SummerRoadTrip (1) ActiveRecord (1) architecture (1) architecture chat (95) ArchitectureCamp2007 (2) asp.net (1) Astoria (1) Auckland (1) base4 (9) batching (1) binsor (1) blog (4) boo (1) books (1) C# 3.0 (9) cambodia (9) CAML.Net (1) castle (40) china (8) codecamp (3) codeplex (3) dapper.net (1) DevDefined Ltd. (4) DirectShow.Net (1) DLR (1) DSL (4) EAUG (1) Enterprise Architect (5) Enterprise Architecture (1) Enterprise Library (1) F# (1) feedburner (2) first post (1) Friendster (1) generics (1) googlegears (1) hacks (3) hardware (3) hongkong (2) Horn (1) hyper-v (1) ideas (1) IoC (21) IronPython (13) IronRuby (2) jobs (1) Languages (2) laos (8) LINQ (7) LiveId (1) LLU (1) Local Government (1) MDA (1) MDD (1) microsoft (1) Model Driven Development (1) mono (1) monorail (2) Movies (1) Music (1) nDepend (1) news (1) NHibernate (3) NUnit (2) nvelocity (1) OAuth (6) office (1) OpenSocial (1) orcon (1) photos (1) php (1) PostSharp (1) powerpoint (1) presentations (1) ReSharper (1) REST (2) rhino commons (3) rhinomocks (5) Ruby (1) SaaS (1) scm (1) Screen Architect (0) SharePoint (5) silverlight (1) Splicer (4) SQL2008 (1) supcom (1) survey (1) svn (1) Syzmk (4) thailand (6) Tools (2) Tortoise SVN (1) trac (2) Travel (36) Unity (2) vietnam (7) vista (2) visual nhibernate (1) vmware (1) volta (3) VS2008 (1) WCF (3) wiki (2) wikipedia (1) Windows Server 2008 (1) windsor (6) WinForms (1) wix (2) WPF (2) xmlrpc (1) yahoo pipes (1)
Who am I?
Alex Henderson
Alex Henderson
Auckland, New Zealand
Managing Director at Dev|Defined Limited

"Self Confessed Coding Junky for 15 years"
View Alex Henderson's profile on LinkedIn
 
Mobile: +64-21-402-969
Email: bittercoder 'at' gmail 'dot' com
MSN: bittercoder_nz@hotmail
Skype: alex.devdefined
Navigation