如何一般地为属性创建表达式?

时间:2016-09-29 00:40:47

标签: c# lambda

ExpressMapper有一个Ignore方法,如下所示:

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;
}

我想添加自己的IgnoreAll方法,该方法迭代Type上的所有属性,并为每个属性调用Ignore方法。这就是我到目前为止所做的:

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;
}

运行此代码时,出现错误:

  

MemberExpression应该返回目标的一个属性   类

从上面Ignore方法的来源可以看出,我生成的表达式失败了以下条件:

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

所以我的问题是:

在扩展方法中需要更改哪些内容才能生成Expression方法所期望的正确Ignore

编辑:顺便说一句,MemberConfiguration课程的完整来源就在这里:https://github.com/fluentsprings/ExpressMapper/blob/master/ExpressMapper%20NET40/MemberConfiguration.cs

1 个答案:

答案 0 :(得分:1)

好吧,我想出来了,我得告诉你,这是一个很糟糕的事。

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;
}