委托的out/ref参数
本文关键字:ref 参数 out | 更新日期: 2024-09-12 14:13:30
委托:
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; }
}
当我执行这个委托时,我希望在这个函数结束后更改查询,但没有。因此,我假设查询是通过值(而不是通过引用)传递的
但是,当我为这个查询创建一个包装类时,将查询添加到包装类中,并将其传递出去。然后,在这个方法完成后,包装类内部的查询已经更改(所以这个包装类是通过引用传递的?)
这是怎么回事?
您可能混淆了C#"by reference"和C++"by reference"。
在代码中,query
是通过引用传递的,这意味着对query
值的引用是通过值传递的。因此,更改query
将更改引用所引用的值。但是,更改引用本身没有任何作用。
query
是不可变的——没有办法更改值。您只能创建一个新查询,该查询本身包含旧查询。这正是OrderBy
的作用——它不会改变query
。这是LINQ的核心功能之一,也是C#中类似的功能方法——可变代码通常很难以通用的方式处理,所以您希望避免它,尤其是在接口上。
因此,您需要做的是通过引用传递引用,而不是通过值传递引用。这正是您通过提供Wrapper
类所做的。使用ref
关键字也可以做到这一点,但这是完全没有必要的,而且在您的情况下很难处理。ref
只对值类型有意义,尽管即使对于引用类型也有有用的情况;不过,它们相当罕见。
但最好、最简单的方法是遵循简单的原则:不更改任何内容,只返回包含更改的对象。让您的委托返回查询,而不是修改参数:
delegate IQueryable<...> YourDelegate(IQueryable<...> query);
IQueryable<...> YourMethod(IQueryable<...> query)
{
return query.OrderBy(...);
}
它是通过引用传递的,但你不是在引用上操作,而是覆盖它。这就像在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);
};
}