Asked  7 Months ago    Answers:  5   Viewed   40 times
string [] files = new string[2];
files[0] = "ThinkFarAhead.Example.Settings.Configuration_Local.xml";
files[1] = "ThinkFarAhead.Example.Settings.Configuration_Global.xml";

//Resharper complains this is an "access to modified closure"
for (int i = 0; i < files.Length; i++ )
{
    // Resharper disable AccessToModifiedClosure
    if(Array.Exists(Assembly.GetExecutingAssembly().GetManifestResourceNames(),
    delegate(string name) { return name.Equals(files[i]); }))
         return Assembly.GetExecutingAssembly().GetManifestResourceStream(files[i]);
    // ReSharper restore AccessToModifiedClosure
}

The above seems to work fine though ReSharper complains that this is "access to modified closure". Can any one shed light on this?

(this topic continued here)

 Answers

27

In this case, it's okay, since you are actually executing the delegate within the loop.

If you were saving the delegate and using it later, however, you'd find that all of the delegates would throw exceptions when trying to access files[i] - they're capturing the variable i rather than its value at the time of the delegates creation.

In short, it's something to be aware of as a potential trap, but in this case it doesn't hurt you.

See the bottom of this page for a more complex example where the results are counterintuitive.

Tuesday, June 1, 2021
 
Sethunath
answered 7 Months ago
81

GetNames() returns an IEnumerable. So if you store that result:

IEnumerable foo = GetNames();

Then every time you enumerate foo, the GetNames() method is called again (not literally, I can't find a link that properly explains the details, but see IEnumerable.GetEnumerator()).

Resharper sees this, and suggests you to store the result of enumerating GetNames() in a local variable, for example by materializing it in a list:

IEnumerable fooEnumerated = GetNames().ToList();

This will make sure that the GetNames() result is only enumerated once, as long as you refer to fooEnumerated.

This does matter because you usually want to enumerate only once, for example when GetNames() performs a (slow) database call.

Because you materialized the results in a list, it doesn't matter anymore that you enumerate fooEnumerated twice; you'll be iterating over an in-memory list twice.

Monday, June 28, 2021
 
yosemite
answered 6 Months ago
84

Here is a fairly good explanation.

A closure is created when you reference a variable in the body of a method from a delegate. Essentially, a class that contains a reference to the local variable is generated.
If the variable is constantly modified, when an external method calls the delegate, it may contain an unpredictable value, or even throw an exception. For example, in an example like this:

foreach (string data in _dataList)
{
    DoStuff (() => data);
}

The method () => data is always going to be the same method. if you store it, you don't know what happens when it's eventually invoked -- what will the value of data be at the time? Will it even be valid? This is especially dangerous if you use yield return.

A simpler example, without an iterator, is:

var x = 5;
Action f = () => Console.WriteLine(x);
x = 76;
f();
Friday, July 30, 2021
 
Abhishek Gupta
answered 4 Months ago
42

Update: The JetBrains are working on Resharper for C++.

While not quite as good for C++ as Resharper is for C#, Whole Tomato makes a product called Visual Assist X which handles C++ and does it in a reasonably performant manner.

Developer Express also makes CodeRush, which provides more features than Visual Assist, but which is also a much harder drain on your computer, and also which occasionally makes mistakes -- most constructs using macros won't work correctly with CodeRush. Note that as of 2013-05-31, CodeRush has deprecated their C++ support.

Resharper and Visual Assist are nice to have around -- I occasionally flip on CodeRush for some of it's better refactorings, but most of the time leave it off because Visual Assist X's code completion assistance is better.

Do keep in mind that installing any such plugin requires running the IDE in Integrated Mode (rather than Isolated Mode). This means:

  • In Visual Studio 2012 or earlier you'll need a full version of Visual Studio, not one of the express editions. If you're a university student you can probably download a full copy from MSDNAA. If you're a non-university student or your university doesn't provide MSDNAA you can still download a full version from DreamSpark.
  • In Visual Studio 2013 or later you can use the "Community Edition", such as Visual Studio Community 2013.
Monday, August 2, 2021
 
Vlad
answered 4 Months ago
53

You have a very nasty problem that arises from mutating an outer variable to the lambda expression. The problem is this: if you try to iterate eligibleVoters twice (foreach(var voter in eligibleVoters) { Console.WriteLine(voter.Name); } and immediately after (foreach(var voter in eligibleVoters) { Console.WriteLine(voter.Name); }) you will not see the same output. That is just not right from a functional programming perspective.

Here is an extension method that will accumulate until some condition on the accumulator is true:

public static IEnumerable<T> TakeWhileAccumulator<T, TAccumulate>(
    this IEnumerable<T> elements,
    TAccumulate seed,
    Func<TAccumulate, T, TAccumulate> accumulator,
    Func<TAccumulate, bool> predicate
) {
    TAccumulate accumulate = seed;
    foreach(T element in elements) {
        if(!predicate(accumulate)) {
            yield break;
        }
        accumulate = accumulator(accumulate, element);
        yield return element;
    }
}

Usage:

var eligibleVoters = voters.TakeWhileAccumulator(
                         0,
                         (votes, p) => votes + p.Voices, 
                         i => i < 300
                     );

Thus the above says accumulate voices while we have accumulated less than 300 votes.

Then with:

foreach (var item in eligibleVoters) { Console.WriteLine(item.Name); }
Console.WriteLine();
foreach (var item in eligibleVoters) { Console.WriteLine(item.Name); }

Output is:

Alice
Bob
Catherine

Alice
Bob
Catherine
Wednesday, August 4, 2021
 
Pratik
answered 4 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share