1

ExpressMapper has an Ignore method that looks like this:

public IMemberConfiguration<T, TN> Ignore<TMember>(Expression<Func<TN, TMember>> dest)
{
    if (dest == null)
    {
        throw new ArgumentNullException("dst");
    }

    if (!(dest.Body is MemberExpression))
    {
        throw new Exception("MemberExpression should return one of the properties of destination class");
    }
    foreach (var typeMapper in _typeMappers)
    {
        typeMapper.Ignore(dest);
    }
    return this;
}

I would like to add my own IgnoreAll method that iterates over all properties on a Type and calls the Ignore method for each property. This is what I have so far:

public static IMemberConfiguration<TSource, TDestination> IgnoreAll<TSource, TDestination>(
    this IMemberConfiguration<TSource, TDestination> config)
{
    var props = typeof (TDestination).GetProperties();

    foreach (var prop in props)
    {
        var propertyInfo = typeof(TDestination).GetProperty(prop.Name);

        var entityParam = Expression.Parameter(typeof(TDestination), "e");
        Expression columnExpr = Expression.Property(entityParam, prop);

        if (propertyInfo.PropertyType != typeof(object))
            columnExpr = Expression.Convert(columnExpr, typeof(object));

        var expression = Expression.Lambda<Func<TDestination, object>>(columnExpr, entityParam);

        config.Ignore(expression);
    }

    return config;
}

When this code is run, I get an error:

MemberExpression should return one of the properties of destination class

As you can see from the source of the Ignore method above, my generated expression is failing the following conditional:

if (!(dest.Body is MemberExpression))
{
    throw new Exception("MemberExpression should return one of the properties of destination class");
}

So my question is:

What do I need to change in my extension method to make the correct Expression that the Ignore method is expecting?

Edit: by the way, the full source for the MemberConfiguration class is here: https://github.com/fluentsprings/ExpressMapper/blob/master/ExpressMapper%20NET40/MemberConfiguration.cs

1
  • The problem is that you add Convert. It's a lot trickier than what you've got, because you need to call generic method from the context where one of the parameters is not known at compile time. Commented Sep 29, 2016 at 0:53

1 Answer 1

1

Okay I figured this out, and I gotta tell ya, it was a doozy.

public static IMemberConfiguration<TSource, TDestination> IgnoreAll<TSource, TDestination>(
    this IMemberConfiguration<TSource, TDestination> config)
{
    // First we'll get the collection of properties to iterate over.
    var props = typeof (TDestination).GetProperties();

    foreach (var prop in props)
    {
        // Get the property information.
        var propertyInfo = typeof(TDestination).GetProperty(prop.Name);

        // Create an expression that points to the property.
        var entityParameter = new ParameterExpression[]
        {
            Expression.Parameter(typeof(TDestination), "e")
        };
        var propertyExpression = Expression.Property(entityParameter[0], prop);

        // Create a Func<,> using the TDestination and the property's type
        // for the Type parameters.
        var funcType = typeof(Func<,>).MakeGenericType(typeof(TDestination), propertyInfo.PropertyType);

        // We need to create an Expression using Expression.Lambda<>, but we
        // don't know the types involved so we have to do this using reflection.
        var lambdaMethod = typeof (Expression)
                .GetMethods()
                .Single(m => m.IsGenericMethod &&
                             m.GetParameters()[0].ParameterType == typeof(Expression) &&
                             m.GetParameters()[1].ParameterType == typeof(ParameterExpression[]));
        var lambdaMethodConstructed = lambdaMethod.MakeGenericMethod(funcType);
        var expression = lambdaMethodConstructed.Invoke(
                null,
                new object[] { propertyExpression, entityParameter });

        // Now we need to construct the Ignore method using the property's Type.
        var ignoreMethod = config.GetType().GetMethod("Ignore");
        var constructed = ignoreMethod.MakeGenericMethod(propertyInfo.PropertyType);

        // Finally, we call the constructed Ignore method, using
        // our expression as the argument.
        constructed.Invoke(config, new object[] { expression });
    }

    return config;
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.