我可能会在这里得到一些downvotes,但我实际上通过正常搜索找到了冲突的信息,并希望得到其他人也能轻易找到的确定答案。
给出当前C#中的属性:
public static IEnumerable<string> foo { get; set; } = new string[] { "bar", "bar2" };
我们知道foo
的默认值将返回上面的数组。如果指定了其他值,则不再使用默认值。但是,如果案件是:
public static IEnumerable<string> foo { get; set; } = GetMyStrings();
我的想法是这个功能如下:
if(foo == null) { foo = GetMyStrings();}
并且foo将保留对象生命周期中第一次运行GetMyStrings()
的值,除非被手动指定的值覆盖。
我的同事坚持认为这可能会导致GC问题,并且GetMyStrings()
的结果可能超出范围并被收集,“重新整理”参数并在整个生命周期内导致多次调用GetMyStrings()
物体。
我们哪个是正确的?
答案 0 :(得分:5)
不,实际上是这样的:
static ClassName()
{
foo = GetMyStrings();
}
编译器生成一个静态构造函数并将赋值调用放在那里(就像它在构造函数中为非静态属性创建一行)。
他正在胡说八道。无论从何处分配实例,分配的实例都不会被垃圾回收。我的同事坚持认为这可能会导致GC问题,并且GetMyStrings()的结果可能超出范围并被收集,“重新整理”参数并在对象的生命周期内导致多次调用GetMyStrings()。 / p>
答案 1 :(得分:0)
写这个
public static IEnumerable<string> Foo { get; set; } = GetMyStrings();
是这个宣言的语法糖
public static IEnumerable<string> Foo { get; set; }
并添加了一个如下所示的静态构造函数:
static MyClass() {
Foo = GetMyStrings();
}
(如果你已经有一个静态构造函数,则会隐式添加Foo = GetMyStrings();
行。)
除此之外,没有区别:once it is time for the class to get initialized,GetMyStrings()
从构造函数中调用,然后它返回的值被分配给Foo
。之后,该值保持不变,直到被另一个替换,或者程序结束。
&#34; renullifying&#34;参数,它永远不会发生在类对象的同一个实例上。当包含该类的应用程序域被卸载时,或者当该类加载到另一个应用程序域时,您可以多次调用GetMyStrings()
,但这与新的C#6语法无关。
最后,如果您不打算在静态构造函数之后更改Foo
,请考虑将其设置为只读:
public static IEnumerable<string> Foo { get; } = GetMyStrings();
答案 2 :(得分:0)
举例说明我的评论,请看这个例子:
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();
}
这个输出是:
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
值:如您所见,IEnumerable&lt;&gt;每次调用时,都会评估使用yield的方法。
Values2:该方法返回List。由于List实现了IEmnumerable,你仍然只是返回List的具体实例(虽然表现为它的IEnumerable接口),因此它只被评估一次。
Values3:我们基本上将.ToList()移到GetValues2()方法之外,并直接在属性上实现它。这里的结果与Values2相同,原因基本相同。
当你返回一个实现IEnumerable的具体对象时,它将被评估一次,但要注意第一个例子。
记住伙计们,Linq是一个观点。如果基础数据发生变化,那么从Linq表达式返回的内容也会发生变化。
重新设置垃圾回收问题:活动对象引用的对象不会被垃圾回收。