gpt4 book ai didi

c# - 我可以对 IQueryable 和 IEnumerable 执行 Contract.Ensures 吗?

转载 作者:行者123 更新时间:2023-11-30 12:31:30 24 4
gpt4 key购买 nike

让我们看看这段代码:

public IQueryable<Category> GetAllActive()
{
Contract.Ensures(Contract.Result<IQueryable<Category>>() != null);
return dataSource.GetCategories(T => T.IsActive);
}

有个小问题。代码契约(Contract)可以这样写吗:

public IQueryable<Category> GetAllActive()
{
Contract.Ensures(Contract.Result<IQueryable<Category>>() != null);
Contract.Ensures(Contract.Result<IQueryable<Category>>().All(T => T.IsActive));
return dataSource.GetCategories(T => T.IsActive);
}

还是不行?

这样会不会产生不必要的序列枚举,这是非常不希望的?

最佳答案

假设您正在使用二进制重写器并在运行时执行契约,您不应该这样做。

当您使用 Contract.Ensures 时像这样:

Contract.Ensures(Contract.Result<T>() <operation>);
return expression;

它被转换并且操作被提升为如下所示:

T expression = <expression>;

// Perform checks on expression.
if (!(expression <operation>) <throw appropriate exception>;

// Return value.
return expression;

在这种情况下,这意味着您的代码展开为:

IQueryable<Category> temp = dataSource.GetCategories(T => T.IsActive);

// Perform checks.
if (!(temp != null)) throw new Exception();
if (!temp.All(T => T.IsActive)) throw new Exception();

// Return values.
return temp;

在这种情况下,您的 IQueryable<Category> 将被迭代并导致另一个请求被发送到底层数据存储。

根据操作的不同,您可能不会注意到它,但查询肯定会执行两次,这对性能不利。

对于这种性质的东西,你应该在IQueryable<T>的消费点进行检查无论您是否有任何元素(您可以使用设置为 foreach 的 bool 标志来完成它,或者当您具体化它时)。

但是,如果您没有在编译的程序集上运行二进制重写器,那么 Contract.Result<T> 这种性质的契约(Contract)不能执行;在这种情况下,它是一个 noop,可能不应该存在,因为它没有做任何事情。

关于c# - 我可以对 IQueryable 和 IEnumerable 执行 Contract.Ensures 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13417139/

24 4 0