AutoMapper为Func键的选择类型之间 [英] AutoMapper for Func's between selector types

查看:140
本文介绍了AutoMapper为Func键的选择类型之间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两种类型:。我想选择使用 Func键&LT猫,狗,布尔> 。要做到这一点,我需要一种方法来从猫犬在某种映射器的性能(类似于如何 AutoMapper 从一个对象映射属性映射另一种类型的对象)。

I have two types: Cat and Dog. I'd like to select Cats using a Func<Dog, bool>. To do that, I need a way to map the properties from Cat to Dog in some sort of mapper (similar to how AutoMapper maps properties from one object to another type of object).

我想象这样的事情:

public Cat GetCat(Func<Dog, bool> selector)
{
    Func<Cat, bool> mappedSelector = getMappedSelector(selector);
    return _catRepository.Get(mappedSelector);
}

private Func<Cat, bool> getMappedSelector(Func<Dog, bool> selector)
{
    //some code here to map from one function type to another

    //something like AutoMapper would be sweet... 
    //something that I can configure how I want the properties to be mapped.
}

无论是有一些已经做这个还是应该有。

Either there's already something that does this or there should be.

推荐答案

下面是一个使用AutoMapper一个解决方案:

Here's a solution using AutoMapper:

Func<Cat, bool> GetMappedSelector(Func<Dog, bool> selector)
{
    Func<Cat, Dog> mapper = Mapper.CreateMapExpression<Cat, Dog>().Compile();
    Func<Cat, bool> mappedSelector = cat => selector(mapper(cat));
    return mappedSelector;
}

更新:它已经1.5年因为我第一次回答了这一点,我想我会在我的答案扩大,因为现在人们都在问如何做到这一点,当你有一个前pression而不是委托。

UPDATE: It's been 1.5 years since I first answered this, and I figured I'd expand on my answer now since people are asking how to do this when you have an expression as opposed to a delegate.

的解决方案是在原则上是相同的 - 我们需要能够组成中的两个函数( 选择映射)到一个单一的功能。不幸的是,因为在C#中没有办法呼一前pression从另一个(类似我们可以与代表),我们不能直接在重新code present这一点。例如,下面的code将无法进行编译:

The solution is the same in principle - we need to be able to compose the two functions (selector and mapper) into a single function. Unfortunately, since there's no way in C# to "call" one expression from another (like we could with delegates), we can't directly represent this in code. For example, the following code will fail to compile:

Expression<Func<Cat, bool>> GetMappedSelector(Expression<Func<Dog, bool>> selector)
{
    Expression<Func<Cat, Dog>> mapper = Mapper.CreateMapExpression<Cat, Dog>();
    Expression<Func<Cat, bool>> mappedSelector = cat => selector(mapper(cat));
    return mappedSelector;
}

要创造我们的组成功能的唯一途径,因此,是建立起来的的前pression树使用 System.Linq.Ex pressions 的自己。

The only way to create our composed function, therefore, is to build up the expression tree ourselves using the System.Linq.Expressions classes.

我们真正需要做的是修改选择函数体中,这样它的参数的所有实例是由映射功能。这将成为我们新的函数体,这将接受映射的参数。

What we really need to do is to modify the body of the selector function so that all instances of its parameter are replaced by the body of the mapper function. This will become the body of our new function, which will accept mapper's parameter.

要代替我创建防爆pressionVisitor 类,它可以遍历前pression树,并用任意前pression更换单个参数:

To replace the parameter I created a subclass of ExpressionVisitor class that can traverse an expression tree and replace a single parameter with an arbitrary expression:

class ParameterReplacer : ExpressionVisitor
{
    private ParameterExpression _parameter;
    private Expression _replacement;

    private ParameterReplacer(ParameterExpression parameter, Expression replacement)
    {
        _parameter = parameter;
        _replacement = replacement;
    }

    public static Expression Replace(Expression expression, ParameterExpression parameter, Expression replacement)
    {
        return new ParameterReplacer(parameter, replacement).Visit(expression);
    }

    protected override Expression VisitParameter(ParameterExpression parameter)
    {
        if (parameter == _parameter)
        {
            return _replacement;
        }
        return base.VisitParameter(parameter);
    }
}

然后创建一个扩展方法,撰写(),使用访问者组成两个拉姆达前pressions,外部和内部:

Then I created an extension method, Compose(), that uses the visitor to compose two lambda expressions, an outer and an inner:

public static class FunctionCompositionExtensions
{
    public static Expression<Func<X, Y>> Compose<X, Y, Z>(this Expression<Func<Z, Y>> outer, Expression<Func<X, Z>> inner)
    {
        return Expression.Lambda<Func<X ,Y>>(
            ParameterReplacer.Replace(outer.Body, outer.Parameters[0], inner.Body),
            inner.Parameters[0]);
    }
}

现在,随着地方所有的基础设施,我们可以修改我们的 GetMappedSelector()方法来使用我们的撰写()扩展:

Now, with all that infrastructure in place, we can modify our GetMappedSelector() method to use our Compose() extension:

Expression<Func<Cat, bool>> GetMappedSelector(Expression<Func<Dog, bool>> selector)
{
    Expression<Func<Cat, Dog>> mapper = Mapper.CreateMapExpression<Cat, Dog>();
    Expression<Func<Cat, bool>> mappedSelector = selector.Compose(mapper);
    return mappedSelector;
}

我创建了一个简单的控制台应用程序测试了这一点。但愿,我的解释是不是太模糊;但遗憾的是,没有真正做你想要做什么简单的方法。如果你仍然完全糊涂了,至少可以重复使用我的code,并已获得了AP preciation处理前pression树的细微差别和复杂性!

I created a simple console application to test this out. Hopefully, my explanation was not too obfuscated; but unfortunately, there isn't really a simpler approach to doing what you're trying to do. If you are still totally confused, at least you can reuse my code and have gained an appreciation for the nuances and complexities of dealing with expression trees!

这篇关于AutoMapper为Func键的选择类型之间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆