代表:
return delegate( IQueryable<MySearchResultItem> query, Expression<Func<MySearchResultItem, object>> lambda, Wrapper wrapper)
{
wrapper.query = query.OrderBy(lambda);
query = query.OrderBy(lambda);
};
包装类:
public class Wrapper
{
public IQueryable<MySearchResultItem> query { get; set; }
}
当我执行此委托时,我希望在此功能结束后更改查询,但它没有。所以我假设通过值传递的查询(而不是通过引用)
但是当我为这个查询创建一个包装类时,将查询添加到包装类中并同时传递它。然后在这个方法完成之后,包装类中的查询已经改变了(所以这个包装类是通过引用传递的?)
这里发生了什么?
答案 0 :(得分:1)
它通过引用传递,但您不是在引用上操作而是覆盖它。当你为指针分配一个新地址而不是操作指针的值时,就像在C中一样。它适用于包装类,因为您处理引用而不是覆盖它。
如果您想修改引用,请使用ref
运算符。
return delegate( ref IQueryable<MySearchResultItem> query,
修改:当然,这需要具有匹配的代理签名,并且无法使用Func<T1,T2, TResult>
。
public delegate void MyDelegate(ref IQueryable<object> query, Expression<Func<object, object>> lambda);
private MyDelegate Create()
{
return delegate(ref IQueryable<object> query, Expression<Func<object, object>> lambda)
{
query = query.OrderBy(lambda);
};
}
答案 1 :(得分:1)
你可能会混淆C#&#34;参考&#34;用C ++&#34;参考&#34;。
在您的代码中,query
通过引用传递,这意味着对query
的值的引用是按值传递的。因此,更改query
将更改引用引用的值。但是,更改引用本身不起作用。
query
是不可变的 - 没有办法改变价值。您只能创建一个新查询,其中包含旧查询。而这正是例如OrderBy
确实 - 它不会更改query
。这是LINQ的核心功能之一,C#中的类似功能方法 - 一般来说,可变代码通常难以处理,所以你要避免它,特别是在接口上。
所以你需要做的是通过引用传递引用,而不是通过值传递引用。这正是您通过提供Wrapper
课程所做的事情。也可以使用ref
关键字来执行此操作,但这完全没有必要,而且在您的情况下很难处理。 ref
只对值类型有意义,尽管对于引用类型也有用处;但它们很少见。
但最好和最简单的方法就是遵循简单的原则:不要改变任何东西,只返回包含变化的对象。让你的委托返回查询,而不是修改参数:
delegate IQueryable<...> YourDelegate(IQueryable<...> query);
IQueryable<...> YourMethod(IQueryable<...> query)
{
return query.OrderBy(...);
}