【问题标题】:Selecting as expression from a single object从单个对象中选择表达式
【发布时间】:2014-03-16 08:07:04
【问题描述】:

如何将表达式应用于单个项目?现在我有一个表达式可以在列表或任何支持 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
        }; 

有了这个表达式,我可以做这样的事情:

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

【问题讨论】:

  • 这是否意味着您实际上从数据库中检索了完整的Book 对象?通常,使用 DTO 类的方式是直接投影到它们,就像您在第一个示例中所做的那样。做你要求的是可能的,但可能不是你想要的,因为它的行为方式不同:例如,x.Author.Name 会突然导致 NullReferenceException 如果 x.Author == null (即使作者是在数据库中设置)。你能解释一下你想何时以及如何使用你的SampleMethod吗?
  • 是的,我尝试这样做的原因是因为我使用 FirstOrDefault 从数据库中取回了一个项目(包括将在表达式中使用的所有对象),然后取决于检索到的对象的状态,我将选择对其应用哪个表达式以将其转换为 Dto。假设检索到的对象具有 Inviter 和 Invitee 属性(pocos),现在根据状态我将使用 AsInviterToDto 或 AsInviteeToDto。
  • 另一种方法是使用 AutoMapper。此时,您可以在代码中选择要应用的映射。

标签: c# .net linq


【解决方案1】:

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

public static TOutput SelectSingle<TInput, TOutput>(
    this TInput obj,
    Expression<Func<TInput, TOutput>> expression)
{
    return expression.Compile()(obj);
}

用作:

public BookDto SampleMethod(Book propertiesIncludedBook)
{
    return propertiesIncludedBook.SelectSingle(AsBookDto);
}

省略了错误检查,但正如您所见,像这样直接使用它并没有什么好处:

public BookDto SampleMethod(Book propertiesIncludedBook)
{
    return AsBookDto.Compile()(propertiesIncludedBook);
}

Edit 使用单独的 Func&lt;Book, BookDto&gt; 的替代拆分表达式定义有效,但使表达式本身毫无用处。已删除。

【讨论】:

  • 您的替代方案永远不会起作用,表达式树将不再包含任何有用的信息,它只会包含“调用变量AsBookDtoFunc”,而没有关于AsBookDtoFunc 做什么的信息。但是您的第一个建议似乎无法进一步改进。
  • 感谢您的回答,您提供的第一个示例出现错误。它对我说 expression.Compile() 有 2 个构造函数,一个是默认的空构造函数,另一个接受 System.RunTime.CompilerServices.DebugInfoGenerator 对象,其中没有一个对 'TInput obj' 有效
  • 我能够通过将 expression.Compile() 部分更改为 ´Func fun = expression.Compile();返回乐趣(obj);'
  • @neo112 我认为阿德里亚诺的意思是expression.Compile()(obj)。不过,你想出的结果会完全一样。
  • @hvd 非常正确,这样表达本身就没有意义了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-17
相关资源
最近更新 更多