在Lin和Where调用中重用Linq到实体的表达式<Func <T,TResult>

Ped*_*dro 13 c# linq lambda delegates

假设我有一个实体对象定义为

public partial class Article  
{  
    public Id
    {
        get;
        set;
    }  
    public Text
    {
        get;
        set;
    }  
    public UserId
    {
        get;
        set;
    }  
}
Run Code Online (Sandbox Code Playgroud)

根据文章的某些属性,我需要确定某个用户是否可以删除该文章.所以我添加了一个静态方法来进行检查.就像是:

public partial class Article  
{  
    public static Expression<Func<Article, bool>> CanBeDeletedBy(int userId)
    {  
        //Add logic to be reused here
        return a => a.UserId == userId;
    }  
}
Run Code Online (Sandbox Code Playgroud)

所以现在我能做到

using(MyEntities e = new MyEntities())  
{
    //get the current user id
    int currentUserId = 0;

    e.Articles.Where(Article.CanBeDeletedBy(currentUserid));  
}
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.现在我想在执行Select时重用CanBeDeletedBy中的逻辑,例如:

using(MyEntities e = new MyEntities())  
{
    //get the current user id
    int currentUserId = 0;

    e.Articles.Select(a => new  
    {  
        Text = a.Text,  
        CanBeDeleted = ???  
    };  
}
Run Code Online (Sandbox Code Playgroud)

但无论我尝试什么,我都不能在select方法中使用表达式.我想如果我能做到的话

    e.Articles.Select(a => new  
    {  
        Text = a.Text,  
        CanBeDeleted = a => a.UserId == userId
    };  
Run Code Online (Sandbox Code Playgroud)

然后我应该能够使用相同的表达式.试图编译表达式并通过执行调用它

    e.Articles.Select(a => new  
    {  
        Text = a.Text,  
        CanBeDeleted = Article.CanBeDeletedBy(currentUserId).Compile()(a)
    }; 
Run Code Online (Sandbox Code Playgroud)

但它也不会起作用.

有关如何使其工作的任何想法?或者,如果不可能,在两个地方重用业务逻辑的替代方案是什么?

谢谢

佩德罗

Mar*_*ell 4

重复使用表达式树是一门黑术;你可以做到这一点,但你需要将大量代码切换到反射,并且你会失去所有静态检查。特别是,使用匿名类型变成了一场噩梦(尽管dynamic在 4.0 中可能可行)。

此外,如果您作弊并使用Expression.Invoke,则并非所有提供程序都支持它(最明显的是 .NET 3.5SP1 中的 EF 不支持)。

除非这是一个主要的痛点,否则我会保留重复的内容。或者您需要重新使用表达式树吗?