我正在编写一些东西,我正在将一个字符串传递给构造函数。生成字符串的方式不会以任何方式更改,但它(当我在Visual Studio社区中运行调试工具时)会在第一次丢失该值,但在其他时间显示值。间歇性地,该值报告字符串为空,或者应该是值。
现在,我真的不知道如何准确记录我正在做的事情,所以这是基础知识。
第一部分是TempDir的定义。我正在使用这些临时目录作为测试目录,当TempDir(和测试)超出范围时,它会自动自杀并删除内容。
最终,工作,没有价值的版本
public class TempDir : IDisposable
{
private readonly string _path;
public string ActiveDirectory => _path.Substring(_path.LastIndexOf('/') + 1, (_path.Length - _path.LastIndexOf('/') - 1));
public string Path
{
get
{
return _path;
}
}
public TempDir(string path) : this(path, false) { }
public TempDir(string path, bool KillExisting)
{
_path = path;
if(!KillExisting)
return;
if(Directory.Exists(_path))
Directory.Delete(_path);
}
public void Dispose( )
{
if(System.IO.Directory.Exists(_path))
Directory.Delete(_path, true);
}
public static implicit operator String(TempDir dir) => dir._path;
}
现在,这是我发送给构造函数的代码。 TempDir的ActiveDirectory被发送到构造函数,其中NameOfThing应该是第一个参数的结果,第二个参数也是一个字符串。第一个是间歇性工作,第二个总是有效。
TempDir dir = new TempDir(Environment.GetFolderPath(Environment.SpecialFolders.LocalApplicationData) + "/First/Second/NameOfThing")
我对此非常认真,而且据我所知,我认为一条线可能在我不知情的情况下改变了一些东西
编辑:
我现在可以“可靠地”让它每次都通过,但我必须慢慢地遍历每一行代码。正常运行它而不需要通过每一行进行调试都会失败,但每次调试都会慢慢调试。
构建TempDir的代码:
protected static string PackagesLocation = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "/Sloth/Notes/";
protected static TempDir TestPackLoc = new TempDir(PackagesLocation + "NPackageTests");
protected static NPackage TestPack = new NPackage(TestPackLoc.ActiveDirectory);
创建页面的测试方法
[TestMethod]
public void GeneratesLayoutAndResourcesDirectory( )
{
string key = "GeneratesLayoutAndResourcesDictionary";
TestPack.CreatePage(key);
if(!Directory.Exists(TestPackLoc + "/" + key + "/res") && !Directory.Exists(TestPackLoc + "/" + key + "/layout.xml"))
Assert.Fail( );
}
好吧,我认为丢失值的行为是因为C#不恰当地调用了垃圾收集器。 @mason提到对于TempDir类型,我应该实现IDisposable而不是实现析构函数。现在,它可靠,一致地工作。我不知道为什么实现析构函数会这样做,但是为IDisposable交换它可以正常工作。
解决方案归功于@mason
答案 0 :(得分:1)
这里没有必要使用析构函数。可以使用IDisposable模式。除了实现界面之外,还需要在使用IDisposable
的任何对象中正确处理对象。您可以实施using statement。
using(var tempDir = new TempDir(arguments))
{
//you can use tempDir inside here
} //tempDir's Dispose method is automatically called here
//since tempDir is out of scope here, the directory will have been deleted already
如果某个对象实现了IDisposable,您应该将其包含在上面的using
语句中,或者在Dispose
块中调用其finally
方法以确保它被正确删除。这是try / catch / finally版本的样子:
TempDir tempDir = null;
try
{
tempDir = new TempDir(arguments);
//now you can use tempDir here
}
catch(Exception ex)
{
//log the exception. Optionally rethrow. Do not leave catch block empty
}
finally
{
if(tempDir != null)
{
tempDir.Dispose();
}
}
大多数时候我更喜欢using
块,因为它使变量的范围更清晰。
你可以也使用析构函数来确保如果有人忘记调用Dispose
或将对象包装在非using
块中,而非托管资源(目录)得到妥善清理。
public class TempDir : IDisposable
{
private readonly string _path;
public string ActiveDirectory => _path.Substring(_path.LastIndexOf('/') + 1, (_path.Length - _path.LastIndexOf('/') - 1));
public string Path => _path;
public TempDir(string path) : this(path, false) { }
public TempDir(string path, bool KillExisting)
{
if(string.IsNullOrEmpty(path))
{
throw new ArgumentException($"{nameof(path)} cannot be null or empty.");
}
_path = path;
if(KillExisting && Directory.Exists(_path))
{
Directory.Delete(_path);
}
//why not call Directory.CreateDirectory(_path) here?
}
public void Dispose( )
{
Cleanup();
}
~TempDir()
{
Cleanup();
}
private void Cleanup()
{
if(Directory.Exists(_path))
{
Directory.Delete(_path, true);
}
}
public static implicit operator String(TempDir dir) => dir._path;
}
无需手动将对象设置为null
,因为垃圾收集器将处理为您分配内存。
答案 1 :(得分:0)
您没有正确封装您的私有变量。可能是您在类之外使用公共_path
变量,并且无意中将其设置为其他内容。
TempDir类的改进版本可能如下所示:
public class TempDir
{
private string _path;
public TempDir(string path)
: this(path, false) { }
public TempDir(string path, bool killExisting)
{
_path = path;
if (!killExisting) return;
if (Directory.Exists(_path))
Directory.Delete(_path);
}
public string Path => _path;
public string ActiveDirectory
=> _path.Substring(_path.LastIndexOf('/') + 1,
_path.Length - _path.LastIndexOf('/') - 1);
~TempDir()
{
if (System.IO.Directory.Exists(_path))
Directory.Delete(_path, true);
_path = null;
}
public static implicit operator string(TempDir dir)
{
return dir._path;
}
}