Reputation:
Why does this program show an error for using 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()
{
}
}
Error CS1628 Cannot use ref, out, or in parameter 'seq' inside an anonymous method, lambda expression, query expression, or local function CsharpRefLambdaTest
The problem is with that the parameter seq
is a reference type. But why is it wrong? what't the problem with a reference seq
? If seq
is not reference the program has no errors.
Is there any way to correct the program while keeping seq as a reference?
The program is just an test and it is not going to do anything.
================
I need to use the value of seq
to define a new Sequence seq2
and then assign seq = seq2
. But the values of seq are not usable. If the values of seq
are not going to be usable why does C# allow seq
to be a reference at all?
===============================
Edit:
The program above is just simplified version of the following:
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()
{
}
}
But I don't understand why I cannot remove G
and instead add the defining code of G inside
F`.
Upvotes: 0
Views: 305
Reputation: 1062512
the error message here is: "CS1628 Cannot use ref, out, or in parameter 'seq' inside an anonymous method, lambda expression, query expression, or local function" - seq2
is the lambda expression; it has nothing to do with reference types, but rather: lifetimes. You could, after all, call it like:
void Foo() {
Sequence bar = SomeMethod; // bar is a LOCAL of Foo
F(ref bar);
// not shown: perhaps do something with bar, perhaps not
}
at which point, F
would need to somehow create a lambda that contains within it a reference to a position on the stack (a reference to the local bar
). Now note that this lambda, being an object, could outlive Foo
, and bar
would be an undefined - and possibly reused - memory location.
So: you can't "capture" parameters that are passed as ref
, in
our out
, where I'm using "capture" loosely here to mean "use within the scope of a lambda or anonymous method that forms an expression-tree, delegate expression; or within an iterator block or async continuation".
Just remove the ref
. You don't need it, and it isn't helping. If your intention is to change the delegate, then consider instead returning the composed delegate.
as an alternative workaround: snapshot the value and capture the snapshot:
void F(ref Sequence seq)
{
var tmp = seq;
seq = r =>
{
if (r % 2 == 0)
return tmp(r);
else
return tmp(2 * r);
};
}
this avoids the problematic scenario because the snapshot dereferences the ref
parameter, meaning: there is now no possibility that we're capturing a stack location.
Upvotes: 4