委托的out / ref参数

时间:2016-04-15 07:51:50

标签: c# pass-by-reference pass-by-value

代表:

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

当我执行此委托时,我希望在此功能结束后更改查询,但它没有。所以我假设通过值传递的查询(而不是通过引用)

但是当我为这个查询创建一个包装类时,将查询添加到包装类中并同时传递它。然后在这个方法完成之后,包装类中的查询已经改变了(所以这个包装类是通过引用传递的?)

这里发生了什么?

2 个答案:

答案 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(...);
}
相关问题