4

I might get some downvotes here, but I've actually found conflicting information through normal searches and would like a definitive answer other people can also easily find.

Given a property in current C#:

public static IEnumerable<string> foo { get; set; } = new string[] { "bar", "bar2" }; 

We know that the default value of foo will return as the above array. If another value is assigned, the default value is no longer used. However, what if the case is :

public static IEnumerable<string> foo { get; set; } = GetMyStrings(); 

My thought is that this functions like:

if(foo == null) { foo = GetMyStrings();} 

and that foo will retain the value from its first run of GetMyStrings() for the lifetime of the object unless overwritten by a manually assigned value.

My colleague insists this risks a GC problem, and that the result of GetMyStrings() can fall out of scope and be collected, "renullifying" the parameter and causing multiple calls to GetMyStrings() over the lifetime of the object.

Which of us is correct?

6
  • Can you assign a string to an IEnumerable<string>? Commented Apr 19, 2017 at 12:14
  • That was me flubbing the example because coffee == null. Fixing. Commented Apr 19, 2017 at 12:14
  • please correct your example to be atleast compilalble? Commented Apr 19, 2017 at 12:16
  • Fixed the example to something that would actually make sense. Commented Apr 19, 2017 at 12:17
  • 1
    Well, if you used the proper names for things, it would probably help. They're not defaults, they're the initializer. Commented Apr 19, 2017 at 12:19

3 Answers 3

5

No, actually it is like this:

static ClassName() { foo = GetMyStrings(); } 

The compiler generates a static constructor and puts the assignment call in there (just like it creates a line in the constructor for non-static properties).

My colleague insists this risks a GC problem, and that the result of GetMyStrings() can fall out of scope and be collected, "renullifying" the parameter and causing multiple calls to GetMyStrings() over the lifetime of the object.

He is talking nonsense. An assigned instance will never be garbage collected, no matter from where exactly it was assigned.

Sign up to request clarification or add additional context in comments.

6 Comments

Which is enough right? The 'static' instance will never get dropped and so the assigned static members won't.
Thanks. The same colleague once told me he doesn't use Linq because it's "not been around long enough yet". 3 years ago. I get lunch for free today.
LINQ was released with C# 3, which was in 2007. It is 10 years old already. For most technology already at the end of their lifetime ;) @CDove
@CDove whaaaaattt!?! <3 LINQ, has changed my programming style completely when I started using it a few months ago
Ever had one of those coworkers who swore anything that is newer than the point at which they best understood their craft is automatically the devil's magic? I win a lot of bets...
|
0

Writing this

public static IEnumerable<string> Foo { get; set; } = GetMyStrings(); 

is syntactic sugar over this declaration

public static IEnumerable<string> Foo { get; set; } 

and an addition of static constructor that looks like this:

static MyClass() { Foo = GetMyStrings(); } 

(if you already have a static constructor, Foo = GetMyStrings(); line is added to it implicitly).

Other than that, there is no difference: once it is time for the class to get initialized, GetMyStrings() is called from the constructor, then the value it returns is assigned to Foo. After that the value remains there until it is replaced by another one, or the program ends.

As far as "renullifying" the parameter goes, it never happens to the same instance of the class object. You can get multiple calls to GetMyStrings() when app domain containing the class gets unloaded, or when the class is loaded into another app domain, but that has nothing to do with the new C# 6 syntax.

Finally, if you do not plan to change Foo after the static constructor, consider making it read-only:

public static IEnumerable<string> Foo { get; } = GetMyStrings(); 

Comments

0

To exemplify my comment, look at this example:

public void RunTest() { Test t = new Stackoverflow.Form1.Test(); Console.WriteLine(t.Values.First()); System.Threading.Thread.Sleep(1000); Console.WriteLine(t.Values.First()); System.Threading.Thread.Sleep(1000); Console.WriteLine(t.Values.First()); Console.WriteLine("------"); Console.WriteLine(t.Values2.First()); System.Threading.Thread.Sleep(1000); Console.WriteLine(t.Values2.First()); System.Threading.Thread.Sleep(1000); Console.WriteLine(t.Values2.First()); Console.WriteLine("------"); Console.WriteLine(t.Values3.First()); System.Threading.Thread.Sleep(1000); Console.WriteLine(t.Values3.First()); System.Threading.Thread.Sleep(1000); Console.WriteLine(t.Values3.First()); } public class Test { public IEnumerable<string> Values { get; set; } = GetValues(); public static IEnumerable<string> GetValues() { List<string> results = new List<string>(); for (int i = 0; i < 10; ++i) { yield return DateTime.UtcNow.AddMinutes(i).ToString(); } } public IEnumerable<string> Values2 { get; set; } = GetValues2(); public static IEnumerable<string> GetValues2() { return GetValues().ToList(); } public IEnumerable<string> Values3 { get; set; } = GetValues().ToList(); } 

The output from this is:

19/04/2017 12:24:25 19/04/2017 12:24:26 19/04/2017 12:24:27 ------ 19/04/2017 12:24:25 19/04/2017 12:24:25 19/04/2017 12:24:25 ------ 19/04/2017 12:24:25 19/04/2017 12:24:25 19/04/2017 12:24:25 

Values: As you can see, the IEnumerable<> from the method using yield will be evaluated each time you call it.

Values2: The method returns a List. Since List implements IEmnumerable, you're still just returning the concrete instance of List (albeit presented as its IEnumerable interface) and thus it only gets evaluated once.

Values3: We've basically moved the .ToList() outside of the GetValues2() method and just implemented it directly on the property. The result here is the same as Values2, for basically the same reason.

When you return a concrete object that implements IEnumerable, it will be evaluated once, but watch out for the first example.

And remember folks, Linq is a view. if the underlying data changes, so does what's returned from your Linq expression.


Re the garbage collection question: Objects that are referenced by an active object will not be garbage collected.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.