C# 如何处置一次性捕获的变量?
考虑以下伪代码:C# 如何处置一次性捕获的变量?,c#,lambda,C#,Lambda,考虑以下伪代码: public class SomeComponent { private List<DisposableFoo> _foos = new List<DisposableFoo>(); public void Start() { for (int i = 0; i < 5; i++) { var foo = new DisposableFoo();
public class SomeComponent
{
private List<DisposableFoo> _foos = new List<DisposableFoo>();
public void Start()
{
for (int i = 0; i < 5; i++)
{
var foo = new DisposableFoo();
var bar = new DisposableBar(); <-- EXPLICIT DISPOSE NEEDED?
foo.SomeFunc = x => bar.DoSomethingWithX(x);
_foos.Add(foo);
}
}
public void Stop()
{
_foos.ForEach(f => f.Dispose());
}
}
公共类组件
{
私有列表_foos=新列表();
公开作废开始()
{
对于(int i=0;i<5;i++)
{
var foo=新的可处置foo();
var bar=新的可处置bar();bar.DoSomethingWithX(x);
_添加(foo);
}
}
公共停车场()
{
_foos.ForEach(f=>f.Dispose());
}
}
基础设施是否会在拆除过程中处理捕获的可识别变量
澄清:
我不是在问关于管理一次性物品的最佳实践。我的问题更多的是关于基础设施在这种情况下做什么。我的理解是,为了捕获变量,基础设施在幕后创建了一个类型,该类型包含类型为DisposableBar的字段,并接收对“bar”变量中对象的引用。一旦基础结构捕获了该变量,我就觉得这是一个“灰色区域”,在这一点上,谁有责任确定该变量何时不再需要并且可以被处置。如果您在
DisposableBar
中使用了非托管代码,那么它就需要被处置了,否则垃圾收集器将负责管理资源。是和否。正确的做法是手动处理。如果此代码与实际应用程序类似,则应在列表中收集条形图,并在处理完FOO后处理它们。根据实际代码的结构,您可能需要另一种策略。如果该条是非托管资源,则应始终处置它。在大多数情况下,非托管资源包装在托管资源中,例如StreamReader包装非托管文件句柄。在这些情况下,如果dispose模式实现正确,则当托管对象被垃圾收集时,对象将被释放。问题是GC不是确定性的,并且在内存压力下会运行。可能存在这样一种情况:GC不运行,但您的应用程序缺少文件处理程序,但由于GC只关心内存,所以它不运行,并且未处理非托管资源。简短的回答是肯定的。您需要对任何一次性对象调用dispose。这用于清理非托管资源和依赖项
还要注意:垃圾收集器不会在上调用Dispose或查找IDisposable类型
如果它在方法中是一次性的,那么最好使用using
这样的语句
public void Start()
{
for (int i = 0; i < 5; i++)
{
using (var foo = new DisposableFoo())
using (var bar = new DisposableBar())
{
foo.SomeFunc = x => bar.DoSomethingWithX(x);
_foos.Add(foo);
}
}
}
更新:
Michael
Mark
Luke
John
Gabriel
20
Gabriel
20
Michael
Mark
Luke
John
Gabriel
20
Michael
Mark
Luke
John
Gabriel
20
为了根据您的澄清更新答案,我相信您是在问,在处理一次性对象后,从一次性对象检索的变量会发生什么变化。这是一个棘手的行为,在开发一次性类型时应该好好考虑。下面的一些代码显示了类似情况的结果,可能有助于您理解。
也。在开发类型时,应该决定谁对此负责,但在大多数情况下,您提供给客户的任何信息都应该对客户有利,即使在您被处置之后。换句话说,最好的做法是不删除、处置或操纵您在处置时允许您类型的用户检索的任何信息
using System;
using System.Collections.Generic;
namespace Disposable_Variables_Reference
{
class Program
{
static void Main(string[] args)
{
List<string> DCNames = null;
string DCName = string.Empty;
int DCValue;
using (var disposableClass = new DisposableClass())
{
DCNames = disposableClass.Names;
DCName = disposableClass.Name;
DCValue = disposableClass.Value;
foreach (var name in DCNames) Console.WriteLine(name);
Console.WriteLine(DCName);
Console.WriteLine(DCValue);
}
foreach (var name in DCNames) Console.WriteLine(name);
Console.WriteLine(DCName);
Console.WriteLine(DCValue);
Console.Read();
}
public class DisposableClass : IDisposable
{
public List<string> Names { get; set; } = new List<string>() { "Michael", "Mark", "Luke", "John" };
public string Name { get; set; } = "Gabriel";
public int Value { get; set; } = 20;
public void Dispose()
{
Names.Clear();
Name = string.Empty;
Value = 0;
}
}
}
}
private List<string> names = new List<string>() { "Michael", "Mark", "Luke", "John" };
public List<string> Names
{
get { return names.ToList() ; }
set { names = value; }
}
名称是一个列表(引用类型),并且不会重新写入输出
名称是字符串(不可变引用类型),并且被重新写入输出
值为int(值类型),并且被重新写入输出
但是,;如果在Dispose()
方法中重新分配名称
,而不是将其清除,则也将被重新写入。示例仅包括dispose方法更改
public void Dispose()
{
Names = null; //notice here we re-assign Names to null.
Name = string.Empty;
Value = 0;
}
新输出:
Michael
Mark
Luke
John
Gabriel
20
Gabriel
20
Michael
Mark
Luke
John
Gabriel
20
Michael
Mark
Luke
John
Gabriel
20
知道了这一点,公开名称的正确方法是在Dispose()
方法中不使用它,或者像这样公开名称;返回新列表,以便在处理时不会删除对该列表的任何引用
using System;
using System.Collections.Generic;
namespace Disposable_Variables_Reference
{
class Program
{
static void Main(string[] args)
{
List<string> DCNames = null;
string DCName = string.Empty;
int DCValue;
using (var disposableClass = new DisposableClass())
{
DCNames = disposableClass.Names;
DCName = disposableClass.Name;
DCValue = disposableClass.Value;
foreach (var name in DCNames) Console.WriteLine(name);
Console.WriteLine(DCName);
Console.WriteLine(DCValue);
}
foreach (var name in DCNames) Console.WriteLine(name);
Console.WriteLine(DCName);
Console.WriteLine(DCValue);
Console.Read();
}
public class DisposableClass : IDisposable
{
public List<string> Names { get; set; } = new List<string>() { "Michael", "Mark", "Luke", "John" };
public string Name { get; set; } = "Gabriel";
public int Value { get; set; } = 20;
public void Dispose()
{
Names.Clear();
Name = string.Empty;
Value = 0;
}
}
}
}
private List<string> names = new List<string>() { "Michael", "Mark", "Luke", "John" };
public List<string> Names
{
get { return names.ToList() ; }
set { names = value; }
}
private List name=new List(){“迈克尔”、“马克”、“卢克”、“约翰”};
公开名单名称
{
获取{return names.ToList();}
设置{names=value;}
}
当然,这个完整的答案是为了逻辑和澄清。在我给出的DisposableClass
示例中,没有理由使用IDisposable。您是否询问条码是否会自动处置?为什么会这样?仅仅因为您在lambda中使用它?我的理解是,在这种情况下,基础设施会在后台自动创建一个类型,该类型带有一个类型为DisposableBar的本地字段,该字段接收对存储在bar中的对象(即捕获的变量)的引用。我的问题是,基础架构是否检测到它正在捕获一个一次性实例并进行适当的处理?@CaseyChester您有责任确定何时不再需要和处理它。为您处理此问题的框架没有什么特别之处,也没有扫描任何不同的内容,因为对象是IDisposable的。您唯一得到的是额外的语法,比如使用
语句为您处理一次性对象。处置只是最佳做法;这里没有灰色区域或神秘的幕后工作。@CaseyChester如果你问你从一次性对象中提取的变量在一次性对象被处理后会发生什么,那么只要你有对该对象的引用,什么都不会发生。您的一次性对象必须编写独特的代码来破坏这种行为,但要记住这一点;这是可能发生的。@MichaelPuckettII你说“你得到的唯一的东西是额外的语法,比如using语句来为你处理一次性对象。”这和任何人对我这个问题的回答一样接近