失去参数值

时间:2016-12-22 02:10:58

标签: c# windows

我正在编写一些东西,我正在将一个字符串传递给构造函数。生成字符串的方式不会以任何方式更改,但它(当我在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")

This is the first run This is the run immediately after

我对此非常认真,而且据我所知,我认为一条线可能在我不知情的情况下改变了一些东西

编辑:

我现在可以“可靠地”让它每次都通过,但我必须慢慢地遍历每一行代码。正常运行它而不需要通过每一行进行调试都会失败,但每次调试都会慢慢调试。

构建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

2 个答案:

答案 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;
    }
}