views:

570

answers:

2

I'm writing a file generic block for my application and started with using Lambda expressions for managing my rule sets for block generation to avoid the pitfalls of magic strings, configuration hell etc.

Inside my mapping class I have lines similar to:

Map(x => x.Name).Length(20).PadLeft(true).PaddingChar("#");

This works fine and isn't where my question dwells, where I setup saving my information about the expression is in the Map method:

public override IPropertyMap Map(Expression<Func<T, object>> expression)
{
    var propertyMap = new FixedLengthPropertyMap
          {
              //Length = 20,
              //PaddingCharacter = " ",
              PadLeft = false,
              PropertyInfo = ReflectionHelper.GetProperty(expression)
          };

    _properties.Add(propertyMap);

    return propertyMap;
}

_properties is just a List<IPropertyMap> that stores my info where my question from what is the best way to have a real object's data be read from the properties currently I came up with something similar to this:

var map = new AgentMap();
var agent = new Agent {Name = "Bob"};

string output = map.Write(agent);

public override string Write<T>(T agent)
{
    var initial = _properties[0];
    return initial.PropertyInfo.GetValue(agent, null) as string;
}

Is there a better way than using the GetValue method since earlier on I'm using an expression tree?

+1  A: 

I don't see why you really need to use expression trees at all. Just make the Map method take a Func<T, object> and store that:

public override IPropertyMap Map(Func<T, string> fetcher)
{
    var propertyMap = new FixedLengthPropertyMap
          {
              //Length = 20,
              //PaddingCharacter = " ",
              PadLeft = false,
              Delegate = fetcher // Delegate is of type Delegate
          };

    _properties.Add(propertyMap);

    return propertyMap;
}

Then:

public override string Write<T>(T agent)
{
    var initial = _properties[0];
    Func<T, string> fetcher = (Func<T, string>) initial.Delegate;
    return fetcher(agent);
}

Is there any reason you particularly wanted to know the property and use an expression tree?

Jon Skeet
The only reason I started with keeping it as an expression tree is later on if I needed access to the PropertyInfo information perhaps for different types of conversations / parsing, or if I wanted to create some type of default rules based on naming style of the properties / types.
Chris Marisic
Well then it's probably best to keep it as an expression tree, then compile it when you need to... but there's little point in fetching the PropertyInfo if you really just want to call it for the moment :)
Jon Skeet
I'm handling the expression basically like this (I striped some null checking / validation)var body = expression.Body as MemberExpression;var propertyInfo = (PropertyInfo) body.Member;Which later is what I base my .GetValue(..) off of when I actually read from my "bob" agent object, is this pretty much the main way to do this using expressions or am I approaching this the wrong way that I should just be using Func?If I haven't been clear my end goal is to take a List<Agents> and use my mapper to access values directly from the properties of the Agent objects.
Chris Marisic
If you want to use the expression as a delegate, you can just call Compile on it - that's my point. To execute it, you don't need to look at all the bits of it. By all means keep them around for other purposes, but executing is simple.
Jon Skeet
+1  A: 

In part, it depends on what your scenario is. The "simple" answer is to just compile the expression and invoke it, but that has a potential performance impact if you are doing it in a tight loop (passing a delegate would be a lot quicker).

I'm not sure whether if would apply in this particular case (because of the agent), but to avoid doing too much expression compilation, you can look for simple scenarios and read the value directly from the expression tree; a little bit of PropertyInfo/FieldInfo is going to be quicker than compiling it...

For more, look at TryEvaluate here, and how it is used with Compile as a backup strategy (although you have the advantage of a known delegate type).

Marc Gravell