Why does ReSharper tell me "implicitly captured closure"? - c#

I have the following code:
public double CalculateDailyProjectPullForceMax(DateTime date, string start = null, string end = null)
{
Log("Calculating Daily Pull Force Max...");
var pullForceList = start == null
? _pullForce.Where((t, i) => _date[i] == date).ToList() // implicitly captured closure: end, start
: _pullForce.Where(
(t, i) => _date[i] == date && DateTime.Compare(_time[i], DateTime.Parse(start)) > 0 &&
DateTime.Compare(_time[i], DateTime.Parse(end)) < 0).ToList();
_pullForceDailyMax = Math.Round(pullForceList.Max(), 2, MidpointRounding.AwayFromZero);
return _pullForceDailyMax;
}
Now, I've added a comment on the line that ReSharper is suggesting a change. What does it mean, or why would it need to be changed? implicitly captured closure: end, start

The warning tells you that the variables end and start stay alive as any of the lambdas inside this method stay alive.
Take a look at the short example
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
int i = 0;
Random g = new Random();
this.button1.Click += (sender, args) => this.label1.Text = i++.ToString();
this.button2.Click += (sender, args) => this.label1.Text = (g.Next() + i).ToString();
}
I get an "Implicitly captured closure: g" warning at the first lambda. It is telling me that g cannot be garbage collected as long as the first lambda is in use.
The compiler generates a class for both lambda expressions and puts all variables in that class which are used in the lambda expressions.
So in my example g and i are held in the same class for execution of my delegates. If g is a heavy object with a lot of resources left behind, the garbage collector couldn't reclaim it, because the reference in this class is still alive as long as any of the lambda expressions is in use. So this is a potential memory leak, and that is the reason for the R# warning.
#splintor
As in C# the anonymous methods are always stored in one class per method there are two ways to avoid this:
Use an instance method instead of an anonymous one.
Split the creation of the lambda expressions into two methods.

Agreed with Peter Mortensen.
The C# compiler generates only one type that encapsulates all variables for all lambda expressions in a method.
For example, given the source code:
public class ValueStore
{
public Object GetValue()
{
return 1;
}
public void SetValue(Object obj)
{
}
}
public class ImplicitCaptureClosure
{
public void Captured()
{
var x = new object();
ValueStore store = new ValueStore();
Action action = () => store.SetValue(x);
Func<Object> f = () => store.GetValue(); //Implicitly capture closure: x
}
}
The compiler generates a type looks like :
[CompilerGenerated]
private sealed class c__DisplayClass2
{
public object x;
public ValueStore store;
public c__DisplayClass2()
{
base.ctor();
}
//Represents the first lambda expression: () => store.SetValue(x)
public void Capturedb__0()
{
this.store.SetValue(this.x);
}
//Represents the second lambda expression: () => store.GetValue()
public object Capturedb__1()
{
return this.store.GetValue();
}
}
And the Capture method is compiled as:
public void Captured()
{
ImplicitCaptureClosure.c__DisplayClass2 cDisplayClass2 = new ImplicitCaptureClosure.c__DisplayClass2();
cDisplayClass2.x = new object();
cDisplayClass2.store = new ValueStore();
Action action = new Action((object) cDisplayClass2, __methodptr(Capturedb__0));
Func<object> func = new Func<object>((object) cDisplayClass2, __methodptr(Capturedb__1));
}
Though the second lambda does not use x, it cannot be garbage collected as x is compiled as a property of the generated class used in the lambda.

The warning is valid and displayed in methods that have more than one lambda, and they capture different values.
When a method that contains lambdas is invoked, a compiler-generated object is instantiated with:
instance methods representing the lambdas
fields representing all values captured by any of those lambdas
As an example:
class DecompileMe
{
DecompileMe(Action<Action> callable1, Action<Action> callable2)
{
var p1 = 1;
var p2 = "hello";
callable1(() => p1++); // WARNING: Implicitly captured closure: p2
callable2(() => { p2.ToString(); p1++; });
}
}
Examine the generated code for this class (tidied up a little):
class DecompileMe
{
DecompileMe(Action<Action> callable1, Action<Action> callable2)
{
var helper = new LambdaHelper();
helper.p1 = 1;
helper.p2 = "hello";
callable1(helper.Lambda1);
callable2(helper.Lambda2);
}
[CompilerGenerated]
private sealed class LambdaHelper
{
public int p1;
public string p2;
public void Lambda1() { ++p1; }
public void Lambda2() { p2.ToString(); ++p1; }
}
}
Note the instance of LambdaHelper created stores both p1 and p2.
Imagine that:
callable1 keeps a long-lived reference to its argument, helper.Lambda1
callable2 does not keep a reference to its argument, helper.Lambda2
In this situation, the reference to helper.Lambda1 also indirectly references the string in p2, and this means that the garbage collector will not be able to deallocate it. At worst it is a memory/resource leak. Alternatively it may keep object(s) alive longer than otherwise needed, which can have an impact on GC if they get promoted from gen0 to gen1.

For Linq to Sql queries, you may get this warning. The lambda's scope may outlive the method due to the fact that the query is often actualized after the method is out of scope. Depending on your situation, you may want to actualize the results (i.e. via .ToList()) within the method to allow for GC on the method's instance vars captured in the L2S lambda.

You could always figure out with a reasons of R# suggestions just by clicking on the hints like shown below:
This hint will direct you here.
This inspection draws your attention to the fact that more closure
values are being captured than is obviously visibly, which has an
impact on the lifetime of these values.
Consider the following code:
using System;
public class Class1 {
private Action _someAction;
public void Method() {
var obj1 = new object();
var obj2 = new object();
_someAction += () => {
Console.WriteLine(obj1);
Console.WriteLine(obj2);
};
// "Implicitly captured closure: obj2"
_someAction += () => {
Console.WriteLine(obj1);
};
}
}
In the first closure, we see that both obj1 and obj2 are being explicitly captured; we can see this just by looking at the code. For
the second closure, we can see that obj1 is being explicitly captured,
but ReSharper is warning us that obj2 is being implicitly captured.
This is due to an implementation detail in the C# compiler. During
compilation, closures are rewritten into classes with fields that hold
the captured values, and methods that represent the closure itself.
The C# compiler will only create one such private class per method,
and if more than one closure is defined in a method, then this class
will contain multiple methods, one for each closure, and it will also
include all captured values from all closures.
If we look at the code that the compiler generates, it looks a little
like this (some names have been cleaned up to ease reading):
public class Class1 {
[CompilerGenerated]
private sealed class <>c__DisplayClass1_0
{
public object obj1;
public object obj2;
internal void <Method>b__0()
{
Console.WriteLine(obj1);
Console.WriteLine(obj2);
}
internal void <Method>b__1()
{
Console.WriteLine(obj1);
}
}
private Action _someAction;
public void Method()
{
// Create the display class - just one class for both closures
var dc = new Class1.<>c__DisplayClass1_0();
// Capture the closure values as fields on the display class
dc.obj1 = new object();
dc.obj2 = new object();
// Add the display class methods as closure values
_someAction += new Action(dc.<Method>b__0);
_someAction += new Action(dc.<Method>b__1);
}
}
When the method runs, it creates the display class, which captures all values, for all closures. So even if a value isn't used
in one of the closures, it will still be captured. This is the
"implicit" capture that ReSharper is highlighting.
The implication of this inspection is that the implicitly captured
closure value will not be garbage collected until the closure itself
is garbage collected. The lifetime of this value is now tied to the
lifetime of a closure that does not explicitly use the value. If the
closure is long lived, this might have a negative effect on your code,
especially if the captured value is very large.
Note that while this is an implementation detail of the compiler, it
is consistent across versions and implementations such as Microsoft
(pre and post Roslyn) or Mono's compiler. The implementation must work
as described in order to correctly handle multiple closures capturing
a value type. For example, if multiple closures capture an int, then
they must capture the same instance, which can only happen with a
single shared private nested class. The side effect of this is that
the lifetime of all captured values is now the maximum lifetime of any
closure that captures any of the values.

Related

Do Func and Action delegates become null if the source object becomes dereferenced?

Define these variables in Class A:
public int CubeAnInt32(int n)
{
return n * n * n;
}
And these variables in Class B:
public void CubeAnInt32WithDelegate(int k, Func<int, int> delg)
{
return delg(k);
}
And an overall scope:
/// Note that this is outside the scope of SomeArbitraryCallback()
Func<int, int> cube = default;
public void SomeArbitraryCallback()
{
var refWithinScope = new ClassA();
cube = refWithinScope.CubeAnInt32;
return;
}
public void AnotherCallbackPerformedAfter()
{
var cubeDependent = new ClassB();
/// Does this throw a NullReferenceException because of 'cube'?
/// Has the delegate assigned to 'cube' been dereferenced?
var result = cubeDependent.CubeAnInt32WithDelegate(0, cube);
return result;
}
Will a delegate whose object has been "de-scoped" (i.e. cube) be dereferenced? Or will this delegate reference the assigned object and prevent it from being GC'd?
As per https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates/ - "A delegate is a type that represents references to methods" (emphasis is mine).
So as long as your delegate (cube) remains in scope, a reference is held and refWithinScope (of type ClassA) will not be collected.
Whether you want to have this sort of design is a different discussion: looks like a good candidate for introducing subtle, unintended bugs in future re-factors.
A delegate - concerning referencing null- is in no way different from any other type. So if the variable is null and you try to invoke it, you surely get a NullReferenceException.
public event EventHandler<EventArgs> MyEvent;
private void RaiseEvent()
{
MyEvent.Invoke(this, myEventArgs);
}
So of course you need to assign somethig to your delegate, otherwise it's just null.
The same applies to a property. Unless you don't assignt any value to it, it will allways have its default-value, which is null for reference-types:
public string MyString { get; set; }
private void DoSomething()
{
Console.WriteLine(MyString.Length); // crash here
}
Coming back to your code, Func<int, int> cube = default; will just assign null to cube. So when you call CubeAnInt32WithDelegate before having assigned something to the delegate, e.g. by calling SomeArbitraryCallback, you will get an NRE.

What is the impact of C# closures on memory?

I have a class Test which holds two members, one (arr) which takes a lot of memory and the other (b) which doesn't:
public class Test
{
public Test() {
Arr = new int[100000000];
}
public bool B {get; private set;}
public int[] Arr {get; private set;}
}
Later in my code, I want to store a lambda expression this way:
// `test` has been declared somewhere as an instance of Test
Action lambda = () => {
if (test.B)
// Do things
}
What will be the memory consumption of this closure?
Will it hold the whole Test object in its environment, or only Test.b?
Should I do instead:
var tmpB = test.B;
Action lambda = () => {
if (tmpB)
// Do things
}
Will it hold the whole Test object in its environment, or only Test.b?
Well, it will capture the variable test (by creating a separate class to contain that variable), which in turn has a value which is a reference to the instance of Test.
In other words, a method like this:
public Action Foo()
{
Test test = new Test();
Action printB = () => Console.WriteLine(test.b);
return printB;
}
will be converted into something like this:
public Action Foo()
{
CompiledGeneratedClass tmp = new CompilerGEneratedClass();
tmp.test = new Test();
Action printB = tmp.GeneratedMethod;
return printB;
}
private class CompilerGeneratedClass
{
public Test test;
public void GeneratedMethod()
{
Console.WriteLine(test.b)
}
}
So yes, if you don't want the delegate to effectively keep the instance of Test alive, you should pull out the value of the property first. Note that that has two semantic differences though:
If the value of the property changes in the object, you won't see that in the delegate any more
If the value of test itself changes (e.g. to refer to a different instance of Test) you won't see that in the delegate any more
The closure is going to store the value of the test variable, and the test variable is just a reference to an object of type Test elsewhere in memory, since it's not a struct, and that Test object doesn't actually have an integer array, it just has a reference to a large array stored in yet another location in memory.
Since you're holding onto a reference to that instance of Test, the object won't be eligible for garbage collection for as long as the closure isn't eligible for garbage collection. If you pull the boolean value out of the Test object and close over that, as you showed, then you're no longer referencing theTest object. If, as a result of that, nothing has access to the Test instance, or the contained array, then it would become eligible for garbage collection. If there would still be other code that could access it, then that wouldn't be the case, and there'd be no benefit.

Invoking an Action - determine if the instance it belongs to is null

I have a method that takes an Action as a parameter. Actions are stored in a queue and executed when particular resources become available. Before I invoke an Action, I'd like to check if the instance it is a member of is null.
I did a simple test with the following stupid example. The Action invoked successfully after setting the invokee to null, and as expected, I got a NullReferenceException when attempting to access the property on the null invokee. Nothing jumped out at me when examining the Action at runtime that suggested I could determine if its instance was null.
I guess I could pass in the Action and the instance as parameters and test if the instance is null before invoking. Is it possible to test for a null invokee, or is this just a case of bad design on my part?
UPDATE:
I added the line,
if (explosion.Target != null)
to Bazooka.Fire(), to check for a null target, but it is still invoking the delegate in my example.
public void LetsDoThis()
{
var bazooka = new Bazooka();
var rocketLauncher = new RocketLauncher();
bazooka.LockAndLoad(rocketLauncher.BlowStuffUp);
rocketLauncher = null;
bazooka.Fire();
bool wasThisCompletelyAwesome = rocketLauncher.ThisIsAwesome;
}
public class RocketLauncher
{
public void BlowStuffUp()
{
bool stuffIsBlowingUp = true;
}
public bool ThisIsAwesome
{
get
{
return true;
}
}
}
public class Bazooka
{
private List<Action> explosions = new List<Action>();
public void LockAndLoad(Action loadIt)
{
this.explosions.Add(loadIt);
}
public void Fire()
{
foreach (Action explosion in explosions)
if (explosion.Target != null)
explosion.Invoke();
}
}
This won't work.
The Action does not in any way care about the original reference variable you got it from, it makes a copy of the reference value, and thus has its own reference.
Note that this also means that as long as you still have a reference to the delegate, even though you have no other references to the original object, it will still not be eligible for garbage collection.
The .Target property refers to the instance on which the method that the delegate refers to should be invoked, basically the this "parameter" to that method.
Thus, to have a null target you need to get the delegate from a static method, try this in LINQPad:
void Main()
{
Action a = Static.StaticMethod;
(a.Target == null).Dump();
}
public static class Static
{
public static void StaticMethod() { }
}
You can see that the delegate carries its own instance with this LINQPad code:
void Main()
{
Dummy d = new Dummy { Name = "A" };
Action a = d.Method;
d = new Dummy { Name = "B" };
Action b = d.Method;
d = null;
a();
b();
}
public class Dummy
{
public string Name { get; set; }
public void Method()
{
Debug.WriteLine("Name=" + Name);
}
}
The output here will be
Name=A
Name=B
As requested, let me clarify the difference between the instance, the reference, and the variable.
When you construct an object instance, like this:
var rocketLauncher = new RocketLauncher();
What you're doing is calling a method known as a constructor. The return value from this constructor is a reference to the newly constructed object. Basically, it's a pointer, meaning a memory address of where in the memory that object now lives. If it makes it easier to understand the rest of this answer you can consider it to be just a number.
Additionally you declared a variable, rocketLauncher, to hold this reference, this number.
Note that the object is separate from the variable, they're two distinct items. In one place in memory you have an object, in another place you have the variable containing the reference to that object, it's address, that number.
So when you do this:
bazooka.LockAndLoad(rocketLauncher.BlowStuffUp);
Let's simplify it a bit:
Action a = rocketLauncher.BlowStuffUp;
// bazooka.LockAndLoad(a);
let's forget about the part where we call that LockAndLoad method, and look at what happened when we "converted" the method BlowStuffUp into a delegate of type Action.
Basically, two things was "grabbed":
Which method to make the delegate refer to
The object instance on which to call that method
You can liken this to the following code:
MethodReference = rocketLauncher.BlowStuffUp;
object target = rocketLauncher;
// wrap this into a delegate
This now means you have two references to that object, one lives in the rocketLauncher variable, the other now lives inside the delegate.
What you do with that variable does not in any way change the value of that delegate, it still points to the same object as before. Basically it made a copy of that number. That number is still sitting there inside the delegate.
This is pretty much exactly the same as this:
int a = 10;
int b = a;
a = 0;
// b is still 10
So, to conclude, the .Target property of the delegate does not in any way know, or care, about the original variable that you got the delegate from. A copy was made of the reference value from that original variable, into the delegate, and what you do with the variable afterwards makes no difference at all.
So basically:
The instance is the object, it lives somewhere in memory
The reference is basically the address to it, and you can look at it as sort of a number
The variable is one place where you can store that reference
Now, what if you really want to make the delegate depend on the variable, and care about the value it now has, when you get around to calling it?
Well, one way would be to do this:
bazooka.LockAndLoad(delegate
{
if (rocketLauncher != null)
rocketLauncher.BlowStuffUp();
});
This would make an anonymous method, that would capture the variable itself, and then inside that anonymous method you could explicitly check what value the variable has at the time you call the delegate. If this part, about an anonymous method, does not make sense, you should ask another question here (ideally after reading a bit about anonymous methods, captured variables, and looked over some of the existing questions here on SO).
To test out an anonymous method, test the following code in LINQPad:
void Main()
{
object dummy = new object();
Action a = delegate
{
if (dummy != null)
Debug.WriteLine("not null");
else
Debug.WriteLine("null");
};
a();
dummy = null;
a();
}
It will print out:
not null
null
Use the Target property to check:
if(yourAction.Target != null) {
//...
}
Any Delegate type has a property called Target, so you can also use this for other types of delegate.
Update: In fact, when you use your Action to wrap some method of an object, that object won't never be disposed and that means the NullReferenceException can't be thrown in that case Unless you wrap another method of another object and this method has something to do with the null object.
Well, not in any way trying to argue with Lasse's rather detailed response, I would like to throw in my 5 cents on this.
When you invoke the LockAndLoad method of the bazooka class you simply add the method that's passed to the method to the List explosions collection of the bazooka class. Nulling the instantiation of the class whose method you had passed to the LockAndLoad method (in your example 'rocketLauncher') has NO effect on that collection, meaning that the Target property of the specific Action will not become null. You would have to explicitly remove the method from that collection BEFORE nulling the instantiation of the class.
bazooka.Unload(rocketLauncher.BlowStuffUp);
rocketLauncher = null;
Of course this works only if you modified your bazooka class to the following method in your bazooka class:
public void Unload(Action unloadIt)
{
if (explosions.Contains(unloadIt))
explosions.Remove(unloadIt);
}
This may not be what you are hoping for, but I hope it helped anyhow.

Store a reference to a value type?

I am writing a "Monitor" object to facilitate debugging of my app. This Monitor object can be accessed at run time from an IronPython interpreter. My question is, is it possible in C# to store a reference to a value type? Say I have the following class:
class Test
{
public int a;
}
Can I somehow store a "pointer" to "a" in order to be able to check it's value anytime? Is it possible using safe and managed code?
Thanks.
You cannot store a reference to a variable in a field or array. The CLR requires that a reference to a variable be in (1) a formal parameter, (2) a local, or (3) the return type of a method. C# supports (1) but not the other two.
(ASIDE: It is possible for C# to support the other two; in fact I have written a prototype compiler that does implement those features. It's pretty neat. (See http://ericlippert.com/2011/06/23/ref-returns-and-ref-locals/ for details.) Of course one has to write an algorithm that verifies that no ref local could possibly be referring to a local that was on a now-destroyed stack frame, which gets a bit tricky, but its doable. Perhaps we will support this in a hypothetical future version of the language. (UPDATE: It was added to C# 7!))
However, you can make a variable have arbitrarily long lifetime, by putting it in a field or array. If what you need is a "reference" in the sense of "I need to store an alias to an arbitrary variable", then, no. But if what you need is a reference in the sense of "I need a magic token that lets me read and write a particular variable", then just use a delegate, or a pair of delegates.
sealed class Ref<T>
{
private Func<T> getter;
private Action<T> setter;
public Ref(Func<T> getter, Action<T> setter)
{
this.getter = getter;
this.setter = setter;
}
public T Value
{
get { return getter(); }
set { setter(value); }
}
}
...
Ref<string> M()
{
string x = "hello";
Ref<string> rx = new Ref<string>(()=>x, v=>{x=v;});
rx.Value = "goodbye";
Console.WriteLine(x); // goodbye
return rx;
}
The outer local variable x will stay alive at least until rx is reclaimed.
No - you can't store a "pointer" to a value type directly in C#.
Typically, you'd hold a reference to the Test instance containing "a" - this gives you access to a (via testInstance.a).
Here is a pattern I came up with that I find myself using quite a bit. Usually in the case of passing properties as parameters for use on any object of the parent type, but it works just as well for a single instance. (doesn't work for local scope value types tho)
public interface IValuePointer<T>
{
T Value { get; set; }
}
public class ValuePointer<TParent, TType> : IValuePointer<TType>
{
private readonly TParent _instance;
private readonly Func<TParent, TType> _propertyExpression;
private readonly PropertyInfo _propInfo;
private readonly FieldInfo _fieldInfo;
public ValuePointer(TParent instance,
Expression<Func<TParent, TType>> propertyExpression)
{
_instance = instance;
_propertyExpression = propertyExpression.Compile();
_propInfo = ((MemberExpression)(propertyExpression).Body).Member as PropertyInfo;
_fieldInfo = ((MemberExpression)(propertyExpression).Body).Member as FieldInfo;
}
public TType Value
{
get { return _propertyExpression.Invoke(_instance); }
set
{
if (_fieldInfo != null)
{
_fieldInfo.SetValue(_instance, value);
return;
}
_propInfo.SetValue(_instance, value, null);
}
}
}
This can then be used like so
class Test
{
public int a;
}
void Main()
{
Test testInstance = new Test();
var pointer = new ValuePointer(testInstance,x=> x.a);
testInstance.a = 5;
int copyOfValue = pointer.Value;
pointer.Value = 6;
}
Notice the interface with a more limited set of template arguments, this allows you to pass the pointer to something that has no knowledge of the parent type.
You could even implement another interface with no template arguments that calls .ToString on any value type (don't forget the null check first)
You can create ref-return delegate. This is similar to Erik's solution, except instead of getter and setter it use single ref-returning delegate.
You can't use it with properties or local variables, but it returns true reference (not just copy).
public delegate ref T Ref<T>();
class Test
{
public int a;
}
static Ref<int> M()
{
Test t = new Test();
t.a = 10;
Ref<int> rx = () => ref t.a;
rx() = 5;
Console.WriteLine(t.a); // 5
return rx;
}
You can literally take a pointer to a value type using usafe code
public class Foo
{
public int a;
}
unsafe static class Program
{
static void Main(string[] args)
{
var f=new Foo() { a=1 };
// f.a = 1
fixed(int* ptr=&f.a)
{
*ptr=2;
}
// f.a = 2
}
}
class Test
{
private int a;
/// <summary>
/// points to my variable type interger,
/// where the identifier is named 'a'.
/// </summary>
public int A
{
get { return a; }
set { a = value; }
}
}
Why put yourself through all that hassle of writing complicated code, declaring identifiers everywhere linking to the same location? Make a property, add some XML code to help you outside the class, and use the properties in your coding.
I don't know about storing a pointer, don't think it's possible, but if you're just wanting to check its value, the safest way to my knowledge is to create a property of the variable. At least that way you can check its property at any time and if the variable is static, you wouldn't even have to create an instance of the class to access the variable.
Properties have a lot of advantages; type safety is one, XML tags another. Start using them!

Is copying performed when capturing a value-type into a lambda?

struct SomeStruct
{
public int Num { get; set; }
}
class Program
{
static Action action;
static void Foo()
{
SomeStruct someStruct = new SomeStruct { Num = 5 };
action = () => Console.WriteLine(someStruct.Num);
}
static void Main()
{
Foo();
action.Invoke();
}
}
Is a copy of someStruct created when the lambda is created?
Is a copy of someStruct created when Foo returns?
Can I verify that copying doesn't occur? In C++ I'd implement the copy constructor and print from inside it.
Citations from the standard will be appreciated. Any relevant online articles as well.
There will be no copies. Lambdas capture variables, not values.
You can use Reflector to look at the compile code: the compiler will move the "someStruct" variable into a helper class.
private static void Foo()
{
DisplayClass locals = new DisplayClass();
locals.someStruct = new SomeStruct { Num = 5 };
action = new Action(locals.b__1);
}
private sealed class DisplayClass
{
// Fields
public SomeStruct someStruct;
// Methods
public void b__1()
{
Console.WriteLine(this.someStruct.Num);
}
}
Copying structures will never cause user-defined code to run, so you cannot really check it that way.
Actually, the code will do a copy when assigning to the "someStruct" variable. It would do that even for local variables without any lambdas.
It won't be copied, it creates a closure. Basically it'll encapsulate the structure in one object instead of creating it on the stack.
If you want to be sure you can always use reflector, but there is no need for that, the behavior is explained on Raymond Chen blog.
See The implementation of anonymous methods in C# and its consequences (part 1). Your code is actually something like:
class SomeHiddenClass {
SomeStruct someStruct;
someHiddenMethod() {
Console.WriteLine(someStruct.Num);
}
}
SomeHiddenClass someHiddenVar = new SomeHiddenClass();
someHiddenVar.someStruct.Num = 5;
action = someHiddenVar.someHiddenMethod;
No, it doesn't copy, for the same reason (compiler creates a behind the scenes class to hold the value) that a copy of other value types isn't created when you capture a variable in a lambda.
for example, if you do:
int i = 7;
Action a = () => Console.WriteLine("lambda i=" + i);
i++;
a(); //prints 8
Console.WriteLine("main i=" + i); //prints 8
the lambda shares the 'i' with the declaring scope. same thing will happen with your struct. you can do this as a test to prove that copying doesn't occur.

Categories