让我们看看这段代码:
public IQueryable<Category> GetAllActive()
{
Contract.Ensures(Contract.Result<IQueryable<Category>>() != null);
return dataSource.GetCategories(T => T.IsActive);
}
有一个小问题.代码合同是否可以这样写:
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>的消费点.你是否有任何元素(你可以使用一个布尔标志,你通过它设置,或实现它时).
但是,如果您没有在已编译的程序集上运行二进制重写器,则无法执行此类性质的Contract.Result<T>
合同;在这种情况下,它是一个noop,可能不应该在那里,因为它没有做任何事情.