【问题标题】:out / ref parameter for delegate委托的 out / ref 参数
【发布时间】:2016-08-07 01:56:57
【问题描述】:

代表:

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

当我执行此委托时,我希望在此函数结束后更改查询,但事实并非如此。所以我假设查询是按值传递的(而不是通过引用)

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

这是怎么回事?

【问题讨论】:

  • 您将查询重新分配给 query.OrderBy(lambda)。这不会创建一个新的引用,因此输入查询参数不会改变吗?

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


【解决方案1】:

您可能将 C#“按引用”与 C++“按引用”混为一谈。

在您的代码中,query 是通过引用传递的,这意味着对query 的值的引用是通过值传递的。因此,更改query 将更改引用所引用的值。但是,更改引用本身没有任何作用。

query 是不可变的 - 无法更改值。您只能创建一个新查询,该查询本身包含旧查询。这正是例如OrderBy 确实 - 它不会更改 query。这是 LINQ 和 C# 中类似功能方法的核心特性之一 - 可变代码通常更难以一般方式处理,因此您希望避免它,尤其是在接口上。

所以你需要做的是通过引用而不是值传递引用。这正是您通过提供Wrapper 类所做的。也可以使用ref 关键字来执行此操作,但在您的情况下完全没有必要并且很难处理。 ref 仅对值类型才真正有意义,尽管即使对于引用类型也有有用的情况;不过,它们非常罕见。

但是最好和最简单的方法是简单地遵循简单的原则:不要更改任何内容,只需返回一个包含更改的对象。让您的委托返回查询,而不是修改参数:

delegate IQueryable<...> YourDelegate(IQueryable<...> query);

IQueryable<...> YourMethod(IQueryable<...> query)
{
  return query.OrderBy(...);
}

【讨论】:

    【解决方案2】:

    它是通过引用传递的,但是您不是在引用上操作而是覆盖它。就像在 C 中,当您将新地址分配给指针而不是对指针的值进行操作时。它适用于包装类,因为您处理引用而不是覆盖它。

    如果您还想修改引用,请使用ref 运算符。

    return delegate( ref IQueryable<MySearchResultItem> query,
    

    编辑:当然,这需要有匹配的委托签名,它不适用于Func&lt;T1,T2, TResult&gt;。

    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 不应使用 'ref' 关键字声明”
    • @Timon 当然,因为这样做是一个可怕的想法。只需按照惯例并像其他人一样返回新查询。您正在处理函数式编程,并且查询是不可变的。返新,勿改旧。
    • 你能把剩下的代码贴出来吗?它假定您必须为委托匹配某个签名。
    • @Luaan 我同意这是一个可怕的想法。然而,我认为当他没有写扩展时,他有他的理由。所以我所做的只是试图解释为什么他想做的任何事情都行不通。
    猜你喜欢
    • 2010-12-25
    • 2010-12-31
    • 1970-01-01
    • 1970-01-01
    • 2014-10-01
    • 2011-07-26
    • 2012-03-01
    • 2012-08-08
    • 1970-01-01
    相关资源
    最近更新 更多