参考代表类型

问题描述 投票:0回答:1

为什么这个程序显示使用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无法在匿名方法,lambda表达式,查询表达式或本地函数CsharpRefLambdaTest中使用ref,out或参数'seq'

问题在于参数seq是引用类型。但为什么这是错的?参考seq有什么问题?如果seq不是引用,程序没有错误。

有没有办法纠正程序,同时保持seq作为参考?

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

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

我需要使用seq的值来定义一个新的Sequence 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 insideF`的定义代码。

c# lambda delegates
1个回答
4
投票

这里的错误信息是:“CS1628不能在匿名方法,lambda表达式,查询表达式或本地函数中使用ref,out或参数'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将是一个未定义的 - 并且可能重用 - 内存位置。

所以:你不能“捕获”作为ref传递的参数,in我们的out,我在这里松散地使用“捕获”意味着“在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参数,这意味着:现在我们不可能捕获堆栈位置。

© www.soinside.com 2019 - 2024. All rights reserved.