2

I am interested in utilizing lambda expressions to create a tree of property selectors.

The usage scenario is that we have some code that does some recursive reflection on an object graph, and to limit the scope of recursion, we're currently using Attributes to mark which properties should be traversed. i.e. Get all decorated properties of object, if that property is a reference type with decorated properties, repeat for each of those too.

The limitation of using Attributes is that you can only place them on Types you control the source for. A tree of lambda expressions allows the scope to be defined on any arbitrary type's public members.

It would be handy to have a shorthand way to define these expressions, which reflects the structure of the object graph.

Ultimately, I'd love to have something like this:

Selector<MyType> selector = new [] {
        (t => Property1),
        (t => Property2)
        {
                p => NestedProperty1,
                p => NestedProperty2
        }
};

Right now, the best I can do declares an instance for each node explicitly something like this:

var selector = new Selector<MyType>()
{
    new SelectorNode<MyType, Property1Type>(t => Property1),
    new SelectorNode<MyType, Property2Type>(t => Property2)
    {
        new SelectorNode<Property2Type, NestedProperty1Type>(p => NestedProperty1),
        new SelectorNode<Property2Type, NestedProperty2Type>(p => NestedProperty2)
    },
};

There's nothing wrong with this code, but you have to write out the type arguments for each node explicitly, since the compiler can't infer the type arguments. This is a pain. And ugly. I've seen some incredible syntactical sugar out there, and am sure there must be a better way.

Owing to my lack of understanding of 'higher' C# concepts like dynamics, co/contravariant generics and expression trees, I thought I'd pitch the question out there and see if any gurus know of a way to achieve this (or something rather like it?)


For reference, these are the declarations for the Selector and SelectorNode classes that achieve the structure I described in my post:

public interface ISelectorNode<T> {}

public class Selector<T>: List<ISelectorNode<T>>{}

public class SelectorNode<T, TOut>: List<ISelectorNode<TOut>>, ISelectorNode<T> 
{
    public SelectorNode(Expression<Func<T, TOut>> select) {}
}

//Examples of Usage below

public class Dummy
{
    public ChildDummy Child { get; set; }
}

public class ChildDummy
{
    public string FakeProperty { get; set; }
}

public class Usage
{
    public Usage()
    {
        var selector = new Selector<Dummy>
        {
            new SelectorNode<Dummy, ChildDummy>(m => m.Child)
            {
                new SelectorNode<ChildDummy, string>(m => m.FakeProperty)
            }
        };
    }
}

Edited in the interest of expanding on nawal's answer:

Leveraging C#'s collection initializer syntax, we can get code to look like:

var selector = new Selector<Dummy>
  {
      (m => m.Child),
      {dummy => dummy.Child, 
          c => c.FakeProperty,
          c => c.FakeProperty                    
      }
  };

This is if our SelectorNode class' Add method looks like:

public class Selector<T> : List<ISelectorNode<T>>
{
    public SelectorNode<T, T, TOut> Add<TOut>(Expression<Func<T, TOut>> selector, params Expression<Func<TOut, object>>[] children)
    {
        return SelectorNode<T, T, TOut>.Add(this, this, selector);
    }
}

There must be a way to leverage this syntax!

Sebastian Nemeth
  • 5,505
  • 4
  • 26
  • 36

6 Answers6

3

Edit: The below answer of mine unforgivably doesn't answer the question. I somehow misread it. I will provide another answer which could actually do the job. Keeping this answer open as it may help someone in future on something related.


This is something you can manage with a fluent interface, but may not make the cut for you.

Have your selector classes like this:

public class Selector<T> : List<ISelectorNode<T>>
{
    public SelectorNode<T, TOut> Add<TOut>(Expression<Func<T, TOut>> selector)
    {
        return SelectorNode<T, TOut>.Add(this, selector);
    }
}



public class SelectorNode<T, TOut> : List<ISelectorNode<TOut>>, ISelectorNode<T>
{
    //move this common functionality to a third static class if it warrants.
    internal static SelectorNode<T, TOut> Add(List<ISelectorNode<T>> list, Expression<Func<T, TOut>> selector)
    {
        var node = new SelectorNode<T, TOut>(selector);
        list.Add(node);
        return node;
    }



    SelectorNode(Expression<Func<T, TOut>> selector) //unhide if you want it.
    {

    }



    public SelectorNode<TOut, TNextOut> Add<TNextOut>(Expression<Func<TOut, TNextOut>> selector)
    {
        return SelectorNode<TOut, TNextOut>.Add(this, selector);
    }
}

Now you can call:

var selector = new Selector<Dummy>();
selector.Add(m => m.Child).Add(m => m.FakeProperty); //just chain the rest..

I personally find this more readable than your approach in the question, but is not as intuitive or geeky :) I don't think you can have it in one line (sadly :(), but there could be a hard way.

Update:

A one-liner:

public class Selector<T> : List<ISelectorNode<T>>
{
    public SelectorNode<T, T, TOut> Add<TOut>(Expression<Func<T, TOut>> selector)
    {
        return SelectorNode<T, T, TOut>.Add(this, this, selector);
    }
}



public class SelectorNode<S, T, TOut> : List<ISelectorNode<TOut>>, ISelectorNode<T>
{
    //move this common functionality to a third static class if it warrants.
    internal static SelectorNode<S, T, TOut> Add(Selector<S> parent, List<ISelectorNode<T>> list, 
                                                 Expression<Func<T, TOut>> selector)
    {
        var node = new SelectorNode<S, T, TOut>(parent, selector);
        list.Add(node);
        return node;
    }



    Selector<S> parent;

    SelectorNode(Selector<S> parent, Expression<Func<T, TOut>> selector) //unhide if you want it.
    {
        this.parent = parent;
    }



    public SelectorNode<S, TOut, TNextOut> Add<TNextOut>(Expression<Func<TOut, TNextOut>> selector)
    {
        return SelectorNode<S, TOut, TNextOut>.Add(parent, this, selector);
    }

    public Selector<S> Finish()
    {
        return parent;
    }
}

Usage:

var selector = new Selector<Dummy>().Add(m => m.Child).Add(m => m.FakeProperty).Finish();

//or the earlier

var selector = new Selector<Dummy>();
selector.Add(m => m.Child).Add(m => m.FakeProperty); //just chain the rest, no need of Finish

Advantage of first approach:

  1. Simpler

  2. Doesn't alter existing definition (of SelectorNode)

Advantage of second:

  1. Offers a cleaner call.

A small downside of these two approaches could be that now you have an internal static method Add used to share common functionality which has no meaning outside those two selector classes, but that's livable with I guess. You can remove the method and duplicate code (or the hard way, nest SelectorNode inside Selector and hide implementation to outside world if SelectorNode has no meaning outside Selector class. Or even worse make it protected and inherit one class from the other)

A suggestion: You might most probably want to go the composition way than inheritance way with your List<T>s. Your class names (selectors) don't give an idea of a collection beneath it. Good question btw!

Community
  • 1
  • 1
nawfal
  • 70,104
  • 56
  • 326
  • 368
  • Wow, I've never seen an internal static method used this way! I actually don't understand how this works, I've always thought that you can't chain methods on a Constructor call. Can you give me some insight into how exactly this works? – Sebastian Nemeth May 17 '13 at 02:39
  • @Martaver I'm interested to know what you're achieving with this finally. Seem to me a nice idea to utilize compile time safety and reflection. Is this open source (is there a link to the project if so)? – nawfal May 17 '13 at 02:43
  • @Martaver I can, do I need to give it in comments, or update the answer? Actually its simple. The simplest you could do is copy paste my code to your VS, then debug with some sample values using F11. You will see how the pointer moves line by line :) – nawfal May 17 '13 at 02:45
  • 1
    Hi mate, sorry about taking so long to get back to you. I fired up your code in VS and it's very clever. I like the fluent approach for chaining pointers to children, but the problem is (from what I can see) is that this is linear. You go Parent > Child > Property, and then have to call Finish in order to return the scope of the fluency back to 'Parent'. I'm wondering if it's possible to do this in such a way that the children are defined in a params collection of selectors as arguments of the add method. This way multiple children can be defined for each single 'add' call? – Sebastian Nemeth May 23 '13 at 01:52
  • I've edited my question to include some code demonstrating my thoughts, if we use customized Add methods, Expressions and the C# collection initializer, maybe we can take this even further? – Sebastian Nemeth May 23 '13 at 02:20
1

I have to admit at this stage I have gotten numb thinking too many options, hoping this is my last.. :)

Lastly, the one you have mentioned in your question - Expression<Func<T, object>> route. I have no idea how can I better this without losing some compile time safety. Very similar to my first answer:

public class Selector<T> : List<ISelectorNode<T>>
{
    public static SelectorNode<T, TOut> Get<TOut>(Expression<Func<T, TOut>> selector)
    {
        return new SelectorNode<T, TOut>(selector);
    }

    public void Add<TOut>(Expression<Func<T, TOut>> selector)
    {
        var node = new SelectorNode<T, TOut>(selector);
        Add(node);
    }
}



public class SelectorNode<T, TOut> : List<ISelectorNode<TOut>>, ISelectorNode<T>
{

    public SelectorNode(Expression<Func<T, TOut>> selector)
    {

    }

    public ISelectorNode<T> Add(params Expression<Func<TOut, object>>[] selectors)
    {
        foreach (var selector in selectors)
            base.Add(new SelectorNode<TOut, object>(selector));

        return this;
    }

    public ISelectorNode<T> Add(params ISelectorNode<TOut>[] nodes)
    {
        AddRange(nodes);
        return this;
    }
}

And you call:

var selector = new Selector<Person>
{
    Selector<Person>.Get(m => m.Address).Add
    (
        Selector<Address>.Get(x => x.Place),
        Selector<Address>.Get(x => x.ParentName).Add
        (
            x => x.Id,
            x => x.FirstName,
            x => x.Surname
        )
    ),

    Selector<Person>.Get(m => m.Name).Add
    (
        x => x.Id,
        x => x.FirstName,
        x => x.Surname
    ),

    m => m.Age
};

Of all this is my fav until now (if that serves)..

nawfal
  • 70,104
  • 56
  • 326
  • 368
0

Your actual implementation is very clean and readable, may be a tad verbose for your liking - the problem stems from the fact that collection initializer sugar works only when instantiating the collection instance (with new keyword on constructor of course) and sadly C# doesn't infer type from the constructor. Now that rules out what you're trying to do, at least to some extent.

And syntaxes like this

(m => m.Child)
    .SomeAddMethod(c => c.FakeProperty)

do not work without explicitly stating what the lambda actually stands for even if you have extension method SomeAddMethod on Expression<Func<T, TOut>>. I have to say these are sometimes a pita.

What is possible to do is to minimize type specification. The most common approach is to create a static class which will require you provide only the formal parameter type (in your case T) and once the formal parameter type is known the return type (TOut) will be inferred from the argument Expression<Func<T, TOut>>.

Lets take it step by step. Consider a bit more complicated class hierarchy:

public class Person
{
    public Address Address { get; set; }
    public Name Name { get; set; }
    public int Age { get; set; }
}

public class Address
{
    public string Place { get; set; }
    public Name ParentName { get; set; }
}

public class Name
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string Surname { get; set; }
}

Suppose you have this (the simplest):

public class Selector<T> : List<ISelectorNode<T>>
{
    public static SelectorNode<T, TOut> Get<TOut>(Expression<Func<T, TOut>> selector)
    {
        return new SelectorNode<T, TOut>(selector);
    }
}



public class SelectorNode<T, TOut> : List<ISelectorNode<TOut>>, ISelectorNode<T>
{
    internal SelectorNode(Expression<Func<T, TOut>> selector)
    {

    }
}

Now you can add all that manually but with much less parameter typing. Something like this:

var selector = new Selector<Person>();

var pA = Selector<Person>.Get(m => m.Address);
    var aS = Selector<Address>.Get(m => m.Place);
    var aN = Selector<Address>.Get(m => m.ParentName);
        var nI1 = Selector<Name>.Get(m => m.Id);
        var nS11 = Selector<Name>.Get(m => m.FirstName);
        var nS12 = Selector<Name>.Get(m => m.Surname);

var pN = Selector<Person>.Get(m => m.Name);
    var nI2 = Selector<Name>.Get(m => m.Id);
    var nS21 = Selector<Name>.Get(m => m.FirstName);
    var nS22 = Selector<Name>.Get(m => m.Surname);

var pI = Selector<Person>.Get(m => m.Age);

selector.Add(pA);
    pA.Add(aS);
    pA.Add(aN);
        aN.Add(nI1);
        aN.Add(nS11);
        aN.Add(nS12);

selector.Add(pN);
    pN.Add(nI2);
    pN.Add(nS21);
    pN.Add(nS22);

selector.Add(pI);

Very straightforward, but is not as intuitive (I would any day prefer your original syntax to this). May be we could cut this shorter:

public class Selector<T> : List<ISelectorNode<T>>
{
    public static SelectorNode<T, TOut> Get<TOut>(Expression<Func<T, TOut>> selector)
    {
        return new SelectorNode<T, TOut>(selector);
    }

    public Selector<T> Add(params ISelectorNode<T>[] nodes)
    {
        AddRange(nodes);
        return this;
    }
}



public class SelectorNode<T, TOut> : List<ISelectorNode<TOut>>, ISelectorNode<T>
{
    internal SelectorNode(Expression<Func<T, TOut>> selector)
    {

    }



    public ISelectorNode<T> Add(params ISelectorNode<TOut>[] nodes)
    {
        AddRange(nodes);
        return this;
    }
}

Now you can call:

var selector = new Selector<Person>().Add
(
    Selector<Person>.Get(m => m.Address).Add
    (
        Selector<Address>.Get(x => x.Place),
        Selector<Address>.Get(x => x.ParentName).Add
        (
            Selector<Name>.Get(x => x.Id),
            Selector<Name>.Get(x => x.FirstName),
            Selector<Name>.Get(x => x.Surname)
        )
    ), 
    Selector<Person>.Get(m => m.Name).Add
    (
        Selector<Name>.Get(x => x.Id),
        Selector<Name>.Get(x => x.FirstName),
        Selector<Name>.Get(x => x.Surname)
    ),
    Selector<Person>.Get(m => m.Age)
);

Much cleaner, but we could use collection initializer syntax to make it look slightly better. No need of Add(params) method in Selector<T> and you get:

public class Selector<T> : List<ISelectorNode<T>>
{
    public static SelectorNode<T, TOut> Get<TOut>(Expression<Func<T, TOut>> selector)
    {
        return new SelectorNode<T, TOut>(selector);
    }
}

var selector = new Selector<Person>
{
    Selector<Person>.Get(m => m.Address).Add
    (
        Selector<Address>.Get(x => x.Place),
        Selector<Address>.Get(x => x.ParentName).Add
        (
            Selector<Name>.Get(x => x.Id),
            Selector<Name>.Get(x => x.FirstName),
            Selector<Name>.Get(x => x.Surname)
        )
    ),
    Selector<Person>.Get(m => m.Name).Add
    (
            Selector<Name>.Get(x => x.Id),
        Selector<Name>.Get(x => x.FirstName),
        Selector<Name>.Get(x => x.Surname)
    ),
    Selector<Person>.Get(m => m.Age)
};

By having another Add overload in Selector<T> like below you can minimize some more typing, but that's crazy:

public class Selector<T> : List<ISelectorNode<T>>
{
    public static SelectorNode<T, TOut> Get<TOut>(Expression<Func<T, TOut>> selector)
    {
        return new SelectorNode<T, TOut>(selector);
    }

    public void Add<TOut>(Expression<Func<T, TOut>> selector)
    {
        var node = new SelectorNode<T, TOut>(selector);
        Add(node);
    }
}

var selector = new Selector<Person>
{
    Selector<Person>.Get(m => m.Address).Add
    (
        Selector<Address>.Get(x => x.Place),
        Selector<Address>.Get(x => x.ParentName).Add
        (
            Selector<Name>.Get(x => x.Id),
            Selector<Name>.Get(x => x.FirstName),
            Selector<Name>.Get(x => x.Surname)
        )
    ),

    Selector<Person>.Get(m => m.Name).Add
    (
        Selector<Name>.Get(x => x.Id),
        Selector<Name>.Get(x => x.FirstName),
        Selector<Name>.Get(x => x.Surname)
    ),

    m => m.Age // <- the change here
};

This works because the collection initializer can call different Add overloads. But I personally prefer the consistent style of previous call.

Community
  • 1
  • 1
nawfal
  • 70,104
  • 56
  • 326
  • 368
0

Some more (collection initializer) sugar mess:

public class Selector<T> : List<ISelectorNode<T>>
{
    public void Add(params Selector<T>[] selectors)
    {
        Add(this, selectors);
    }

    static void Add<TOut>(List<ISelectorNode<TOut>> nodes, Selector<TOut>[] selectors)
    {
        foreach (var selector in selectors)
            nodes.AddRange(selector);

        //or just, Array.ForEach(selectors, nodes.AddRange);
    }

    public void Add<TOut>(Expression<Func<T, TOut>> selector)
    {
        var node = new SelectorNode<T, TOut>(selector);
        Add(node);
    }

    //better to have a different name than 'Add' in cases of T == TOut collision - when classes 
    //have properties of its own type, eg Type.BaseType
    public Selector<T> InnerAdd<TOut>(params Selector<TOut>[] selectors)
    {
        foreach (SelectorNode<T, TOut> node in this)
            Add(node, selectors);

        //or just, ForEach(node => Add((SelectorNode<T, TOut>)node, selectors));
        return this;
    }
}

public class SelectorNode<T, TOut> : List<ISelectorNode<TOut>>, ISelectorNode<T>
{
    internal SelectorNode(Expression<Func<T, TOut>> selector)
    {

    }
}

Now call it like:

var selector = new Selector<Person>
{
    new Selector<Person>
    {
        m => m.Address
    }.InnerAdd
    (
        new Selector<Address>
        {
            n => n.Place
        },
        new Selector<Address>
        {
            n => n.ParentName
        }.InnerAdd
        (
            new Selector<Name>
            {
                o => o.Id,
                o => o.FirstName,
                o => o.Surname
            }
        )
    ),

    new Selector<Person>
    {
        m => m.Name
    }.InnerAdd
    (
        new Selector<Name>
        {
            n => n.Id,
            n => n.FirstName,
            n => n.Surname
        }
    ),

    m => m.Age
};

Does that help? I don't think so. A lot geeky, but little intuitive. What's worse, no inherent type safety (it's all dependent on what type you provide for the Selector<T> collection initializer).

nawfal
  • 70,104
  • 56
  • 326
  • 368
0

Yet another - no type specification at all, but plain ugly :)

static class Selector
{
    //just a mechanism to share code. inline yourself if this is too much abstraction
    internal static S Add<R, S, T, TOut>(R list, Expression<Func<T, TOut>> selector,
                                         Func<SelectorNode<T, TOut>, S> returner) where R : List<ISelectorNode<T>>
    {
        var node = new SelectorNode<T, TOut>(selector);
        list.Add(node);
        return returner(node);
    }
}



public class Selector<T> : List<ISelectorNode<T>>
{
    public Selector<T> AddToConcatRest<TOut>(Expression<Func<T, TOut>> selector)
    {
        return Selector.Add(this, selector, node => this);
    }

    public SelectorNode<T, TOut> AddToAddToItsInner<TOut>(Expression<Func<T, TOut>> selector)
    {
        return Selector.Add(this, selector, node => node);
    }
}



public class SelectorNode<T, TOut> : List<ISelectorNode<TOut>>, ISelectorNode<T>
{
    internal SelectorNode(Expression<Func<T, TOut>> selector)
    {

    }



    public SelectorNode<T, TOut> InnerAddToConcatRest<TNextOut>(Expression<Func<TOut, TNextOut>> selector)
    {
        return AddToConcatRest(selector);
    }

    public SelectorNode<TOut, TNextOut> InnerAddToAddToItsInnerAgain<TNextOut>(Expression<Func<TOut, TNextOut>> selector)
    {
        return AddToAddToItsInner(selector);
    }

    //or just 'Concat' ?
    public SelectorNode<T, TOut> AddToConcatRest<TNextOut>(Expression<Func<TOut, TNextOut>> selector)
    {
        return Selector.Add(this, selector, node => this);
    }

    public SelectorNode<TOut, TNextOut> AddToAddToItsInner<TNextOut>(Expression<Func<TOut, TNextOut>> selector)
    {
        return Selector.Add(this, selector, node => node);
    }
}

I have given descriptive names to functions to make the intent clear. I'm not going to explain in detail what individually those does, I guess the function names would be enough. Going by the previous example:

var selector = new Selector<Person>();

var pA = selector.AddToAddToItsInner(m => m.Address);
    var aN = pA.InnerAddToConcatRest(m => m.Place);
    var aS = aN.AddToAddToItsInner(m => m.ParentName);
        var nI1 = aS.InnerAddToConcatRest(m => m.Id);
        var nS11 = nI1.AddToConcatRest(m => m.FirstName);
        var nS12 = nS11.AddToConcatRest(m => m.Surname);

var pN = selector.AddToAddToItsInner(m => m.Name);
    var nI2 = pN.InnerAddToConcatRest(m => m.Id);
    var nS21 = nI2.AddToConcatRest(m => m.FirstName);
    var nS22 = nS21.AddToConcatRest(m => m.Surname);

var pI = selector.AddToConcatRest(m => m.Age);

or to give an alternative (to drive the idea home):

var selector = new Selector<Person>();

var pA = selector.AddToAddToItsInner(m => m.Address);
    var aS = pA.InnerAddToConcatRest(m => m.Place);
    var aN = pA.InnerAddToAddToItsInnerAgain(m => m.ParentName);
        var nI1 = aN.InnerAddToConcatRest(m => m.Id);
        var nS11 = nI1.AddToConcatRest(m => m.FirstName);
        var nS12 = nS11.AddToConcatRest(m => m.Surname);

var pN = selector.AddToAddToItsInner(m => m.Name);
    var nI2 = pN.InnerAddToConcatRest(m => m.Id);
    var nS21 = nI2.AddToConcatRest(m => m.FirstName);
    var nS22 = nS21.AddToConcatRest(m => m.Surname);

var pI = selector.AddToConcatRest(m => m.Age);

Now we can combine to make it concise and leave out the redundant variables:

var selector = new Selector<Person>();

selector.AddToConcatRest(m => m.Age).AddToAddToItsInner(m => m.Address)
            .InnerAddToConcatRest(m => m.Place).AddToAddToItsInner(m => m.ParentName)
                .InnerAddToConcatRest(m => m.Id).AddToConcatRest(m => m.FirstName).AddToConcatRest(m => m.Surname);

selector.AddToAddToItsInner(m => m.Name)
            .InnerAddToConcatRest(m => m.Id).AddToConcatRest(m => m.FirstName).AddToConcatRest(m => m.Surname);

Now you may have noticed that many of those Add functions do the same work internally. I separated those methods because from the caller side they have different semantics to perform. If you can know what its doing/meant for then the code can be shorter again. Change SelectorNode<,> class to:

public class SelectorNode<T, TOut> : List<ISelectorNode<TOut>>, ISelectorNode<T>
{
    internal SelectorNode(Expression<Func<T, TOut>> selector)
    {

    }



    public SelectorNode<T, TOut> Add<TNextOut>(Expression<Func<TOut, TNextOut>> selector)
    {
        return Selector.Add(this, selector, node => this);
    }

    public SelectorNode<TOut, TNextOut> AddToAddToItsInner<TNextOut>(Expression<Func<TOut, TNextOut>> selector)
    {
        return Selector.Add(this, selector, node => node);
    }
}

Now usage:

var selector = new Selector<Person>();
selector.AddToConcatRest(m => m.Age).AddToAddToItsInner(m => m.Address)
            .Add(m => m.Place).AddToAddToItsInner(m => m.ParentName)
                .Add(m => m.Id).Add(m => m.FirstName).Add(m => m.Surname);
selector.AddToAddToItsInner(m => m.Name)
            .Add(m => m.Id).Add(m => m.FirstName).Add(m => m.Surname);

Probably there are plenty of other alternatives possible esp when you go for a combination of various approaches. In this particular case of method chaining, if this confuses caller, another possibility is blindly adding from caller side and internally discarding the duplicates. Something like this:

var selector = new Selector<Person>();
selector.Add(m => m.Address).Add(m => m.Place);
selector.Add(m => m.Address).Add(m => m.ParentName).Add(m => m.Id); //at this stage discard duplicates
selector.Add(m => m.Address).Add(m => m.ParentName).Add(m => m.FirstName); //and so on
selector.Add(m => m.Name)... etc
selector.Add(m => m.Age);

For this you will have to introduce your own equality comparer for node class all which makes it extremely fragile.

Another intuitive approach will be to chain the properties directly in the expression. Like:

selector.Add(m => m.Address.Place);
selector.Add(m => m.Address.ParentName.Id);
selector.Add(m => m.Address.ParentName.FirstName); // and so on.

Internally you will need to break the expression down to pieces and build your own expression based on them. If I get time I will make that an answer at some later stage.

nawfal
  • 70,104
  • 56
  • 326
  • 368
0

One thing I have to ask you is why not use reflection and save yourself from the hassle of providing parameters? You can use recursion to traverse through nodes (properties) and manually build trees from there (see threads this or this). This may not give you the kind of flexibility you would want perhaps, though.

Expression is not my strong suit, so take this as pseudo-code. Surely you will have more work to do here.

public class Selector<T> : List<ISelectorNode<object>>
{
    public Selector()
    {
        Add(typeof(T), this);
    }

    void Add(Type type, List<ISelectorNode<object>> nodes)
    {
        foreach (var property in type.GetProperties()) //with whatever flags
        {
            //the second argument is a cool param name I have given, discard-able 
            var paramExpr = Expression.Parameter(type, type.Name[0].ToString().ToLower()); 
            var propExpr = Expression.Property(paramExpr, property);

            var innerNode = new SelectorNode(Expression.Lambda(propExpr, paramExpr));
            nodes.Add(innerNode);
            Add(property.PropertyType, innerNode);
        }
    }
}



public class SelectorNode : List<ISelectorNode<object>>, ISelectorNode<object>
{

    internal SelectorNode(LambdaExpression selector)
    {

    }
}

And usage:

var selector = new Selector<Person>();

Just that's it. This would yield those properties you may not want, like properties on built in types like DateTime, string etc but I think its trivial to bypass them. Or better you could create your own rules and pass them to determine how the traversal should happen.

Community
  • 1
  • 1
nawfal
  • 70,104
  • 56
  • 326
  • 368