C# 从单个对象中选择作为表达式

C# 从单个对象中选择作为表达式,c#,.net,linq,C#,.net,Linq,如何将表达式应用于单个项?现在,我有一个表达式,可以用于支持Select扩展方法的列表或任何集合。我还想将该功能扩展到单个对象。下面是一个例子来阐明我的意思: private static readonly Expression<Func<Book, BookDto>> AsBookDto = x => new BookDto { Title = x.Title, Author = x.

如何将表达式应用于单个项?现在,我有一个表达式,可以用于支持Select扩展方法的列表或任何集合。我还想将该功能扩展到单个对象。下面是一个例子来阐明我的意思:

private static readonly Expression<Func<Book, BookDto>> AsBookDto =
        x => new BookDto
        {
            Title = x.Title,
            Author = x.Author.Name,
            Genre = x.Genre,
            Description = x.Description,
            Price = x.Price,
            PublishDate = x.PublishDate
        }; 

大多数LINQ扩展在
IEnumerable
IQueryable
上工作,在您的情况下,您需要的只是一个普通的函数/委托,但如果您想保持与LINQ相同的语法,只需为此编写您自己的扩展方法:

public static TOutput SelectSingle<TInput, TOutput>(
    this TInput obj,
    Expression<Func<TInput, TOutput>> expression)
{
    return expression.Compile()(obj);
}
省略了错误检查,但正如您所看到的,直接这样使用它并没有什么好处:

IQueryable<BookDto> books = db.Books.Include(b => b.Author)
.Where(x => x.AuthorId == authorId).Select(AsBookDto);
public BookDto SampleMethod(Book propertiesIncludedBook)
{
    //this does not compile because Book does not have a Select method.
    return propertiesIncludedBook.Select(AsBookDto);
}
public BookDto SampleMethod(Book propertiesIncludedBook)
{
    return AsBookDto.Compile()(propertiesIncludedBook);
}

Edit使用单独的
Func
功能的可选拆分表达式定义可以工作,但会使表达式本身变得毫无用处。已删除。

这是否意味着您实际从数据库中检索到了完整的
书籍
对象?通常,DTO类的使用方式是直接投影到它们,就像您在第一个示例中所做的那样。做你要求的是可能的,但可能不是你想要的,因为它的行为方式不同:例如,
x.Author.Name
会突然导致
NullReferenceException
如果
x.Author==null
(即使在数据库中设置了作者,也可能发生这种情况)。您能解释一下何时以及如何使用
SampleMethod
?是的,我之所以尝试这样做,是因为我使用FirstOrDefault从数据库中获取了一个项目(包括表达式中使用的所有对象),然后根据检索到的对象的状态,我将选择应用于该对象的表达式,以将其转换为Dto。假设检索到的对象具有Inviter和Invitee属性(POCO),现在根据状态,我将使用AsInviterTo或AsInviteToTo。另一种方法可能是使用AutoMapper。此时,您可以在代码中选择要应用的映射。您的替代方案将永远无法工作,表达式树将不再包含任何有用的信息,它只会保存“invoke variable
AsBookDtoFunc
”,而不包含有关
AsBookDtoFunc
的功能的信息。但是你的第一个建议看起来无法进一步改进。谢谢你的回答,我在你提供的第一个示例中发现了一个错误。它告诉我expression.Compile()有两个构造函数,一个是默认的空构造函数,另一个接受System.RunTime.CompilerServices.DebugInfoGenerator对象,其中没有一个对'TInput obj'有效。我可以通过更改expression.Compile()使第一个示例工作part to`Func fun=expression.Compile();返回乐趣(obj);我想Adriano的意思是
expression.Compile()(obj)
。不过,您所计算出的结果将以完全相同的方式工作。@hvd非常正确,这样表达式本身就没有意义了。
public BookDto SampleMethod(Book propertiesIncludedBook)
{
    return AsBookDto.Compile()(propertiesIncludedBook);
}