Benjamin
Benjamin

Reputation: 443

In C#, how do you count the number of properties contained within an expression body output function using reflection?

The following is a code block containing the ExpandClause expression body that I'd like to run the count on and I'd like to know how many properties are contained within the resultant object. I'd prefer not to need to instantiate any of these objects if it can be avoided; reflection would be the preference. My use case revolves around a unit test that would fail if more than say 5 properties were contained within an ExpandClause for a given concrete implementation of BaseRepository.

As an example, the below code should output 2 as the ExpandClause is using two properties, e.Name and e.Age.

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

    public string EyeColour { get; set; }

    public int Height { get; set; }

    public string Name { get; set; }
}

public abstract class BaseRepository<TEntity>
{
    protected abstract Expression<Func<TEntity, object>>? ExpandClause { get; }
}

public class PersonRepository : BaseRepository<Person>
{
    protected override Expression<Func<Person, object>>? ExpandClause =>
        e => new
             {
                 e.Name,
                 e.Age
             };
}

Upvotes: 0

Views: 97

Answers (1)

Benjamin
Benjamin

Reputation: 443

I've found a solution that works for me, thanks to @Jeremy's comment.

This class is what counts the members within the Expression:

public class ExpandClauseCounterExpressionVisitor : ExpressionVisitor
{
    public int MemberCount { get; private set; }

    public override Expression Visit(Expression node)
    {
        if (node.NodeType == ExpressionType.Lambda)
        {
            if (node is not LambdaExpression lambdaExpression)
            {
                throw new NullReferenceException(nameof(lambdaExpression));
            }

            if (lambdaExpression.Body is not NewExpression newExpression)
            {
                throw new NullReferenceException(nameof(newExpression));
            }

            MemberCount = newExpression.Members.Count;
        }

        return base.Visit(node) ?? throw new NullReferenceException("Cannot visit a null node");
    }
}

This code is what actually calls the ExpressionVisitor and performs the count check:

var personRepository = new PersonRepository();
var expressionVisitor = new ExpandClauseCounterExpressionVisitor();
_ = expressionVisitor.Visit(personRepository.ExpandClause!);
if (expressionVisitor.MemberCount > 5)
{
    // Do something
}

Upvotes: 1

Related Questions