参考委托人类型

时间:2018-09-03 18:59:27

标签: c# lambda delegates

为什么该程序显示使用seq的错误:

class Program
{
    delegate double Sequence(int r);

    void F(ref Sequence seq) // Here
    {
        Sequence seq2 = r =>
        {
            if (r % 2 == 0)
                return seq(r); // Here
            else
                return seq(2 * r); // Here
        };
        seq = seq2;
    }

    static void Main()
    {
    }
}
  

错误CS1628无法在内部使用ref,out或in参数'seq'   匿名方法,lambda表达式,查询表达式或局部   函数CsharpRefLambdaTest

问题在于参数seq是引用类型。但是为什么会这样呢?引用seq有什么问题?如果未引用seq,则程序没有错误。

在以seq为参考的同时,有什么方法可以纠正程序?

该程序只是一个测试,它不会做任何事情。

================

我需要使用seq的值来定义新的序列seq2,然后分配seq = seq2。但是seq的值不可用。如果seq的值不可用,为什么C#允许seq完全作为引用?

==============================

编辑:

上面的程序只是以下内容的简化版本:

class Program
{
    delegate double Sequence(int r);

    Sequence G(Sequence seq)
    {
        Sequence seq2 = r =>
        {
            if (r % 2 == 0)
                return seq(r);
            else
                return seq(2 * r);
        };
        return seq2;
    }

    void F(ref Sequence seq)
    {
        seq = G(seq);
    }

    static void Main()
    {
    }
}

但是我不明白为什么我不能删除G而添加G inside F`的定义代码。

1 个答案:

答案 0 :(得分:4)

此处的错误消息是:“ CS1628无法在匿名方法,lambda表达式,查询表达式或局部函数内使用ref,out或in参数'seq'”-seq2是lambda表达式;它与引用类型无关,而是:生存期。毕竟,您可以这样称呼它:

void Foo() {
    Sequence bar = SomeMethod; // bar is a LOCAL of Foo
    F(ref bar);
    // not shown: perhaps do something with bar, perhaps not
}

这时,F需要以某种方式创建一个lambda,其中包含对堆栈上某个位置的引用(对本地bar的引用)。现在请注意,作为对象的该lambda可能会超出Foo的寿命,而bar将是未定义的(并且可能会被重用的)内存位置。

因此:您不能“捕获”作为refinout传递的参数,此处我在这里宽松地使用“捕获”来表示“在内部使用构成表达式树,委托表达式的lambda或匿名方法的范围;或者在迭代器块或异步延续中。”

只需删除ref。您不需要它,它也无济于事。如果您打算更改代表,则可以考虑返回组成的代表。


作为替代解决方法:快照值并捕获快照:

void F(ref Sequence seq)
{
    var tmp = seq;
    seq = r =>
    {
        if (r % 2 == 0)
            return tmp(r);
        else
            return tmp(2 * r);
    };
}

这避免了出现问题的情况,因为快照取消引用 ref参数,这意味着:现在我们无法捕获堆栈位置。