失去参数值 [英] Losing argument value

查看:40
本文介绍了失去参数值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我现在正在编码一些东西,我正在将一个字符串传递给构造函数.生成字符串的方式没有任何变化,但它(当我在 Visual Studio 社区中运行调试工具时)第一次丢失该值,但大多数时候显示一个值.间歇性地,该值报告字符串为空,或者它应该是的值.

I am coding something right now, and I am passing a string to the constructor. The manner in which the string is being generated is not changing in any way, but it (when I run the debug tools in Visual Studio Community) loses the value the first time, but shows a value most other times. Intermittently, the value is reporting that the string is null, or the value it should be.

现在,我真的不知道如何准确记录我正在做的事情,所以这里是基础知识.

Now, I really don't know how to document exactly what it is that I am doing, so here's the basics.

第一部分是TempDir的定义.我将这些临时目录用作测试目录,当 TempDir(和测试)超出范围时,这些目录会自动终止并删除内容.

The first part is the definition of TempDir. I am using these temporary directories as testing directories that automatically kill themselves, and delete the contents, when the TempDir (and the test) go out of scope.

最终的、有效的、无丢失价值的版本

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 应该是第一个参数的结果,第二个参数也是一个字符串.第一个间歇性工作,第二个总是工作.

Now, this is the code that I am sending to a constructor. The TempDir's ActiveDirectory is being sent to a constructor, where NameOfThing should be the result of the first argument, and the second argument is also a string. The first one is intermittently working, the second always works.

TempDir dir = new TempDir(Environment.GetFolderPath(Environment.SpecialFolders.LocalApplicationData) + "/First/Second/NameOfThing")

我真的很迷茫,据我所知,我认为一个线程可能会在我不知道的情况下改变我的某些东西

I am seriously so lost on this, and from what I can tell, I think a thread may be changing something on me without my knowing

我现在可以可靠地"每次都通过它,但我必须慢慢地遍历每一行代码.正常运行,不调试每一行,每次都失败,但是调试慢,每次都能通过.

I can now "reliably" get it to pass every time, but I have to slowly walk through every single line of code. Running it normally without debugging through every line fails every time, but debugging slowly makes it pass every time.

构造TempDir的代码:

Code constructing 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 就可以了.

Okay, so the behavior of the lost value was, I think, because C# was calling the garbage collector inappropriately. @mason mentioned that for the TempDir type, instead of implementing a destructor, I should implement the IDisposable. Now, it works reliably, and consistently. I have no clue why implementing the destructor did this, but swapping it out for IDisposable works just fine.

解决方案归功于@mason

Credit for solution goes to @mason

推荐答案

析构函数在这里并不是真正必要的.IDisposable 模式可能是改为使用.它不仅仅是实现接口,您还需要在使用您的 IDisposable 的任何对象中正确处理该对象.您可以实施 using 语句.

A destructor isn't really necessary here. The IDisposable pattern could be used instead. There's more to it than just implementing the interface, you also need to handle the object properly in any object that uses your IDisposable. You can implement a 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 语句中,或者在 finally 中调用它的 Dispose 方法块以确保它被正确删除.这是 try/catch/finally 版本的样子:

Anytime that an object implements IDisposable, you should wrap it in a using statement like above, or call its Dispose method in a finally block to make sure it gets removed properly. Here's what the try/catch/finally version would be like:

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 块,因为它使变量的范围更清晰.

Most of the time I prefer the using block, because it makes the scope of the variable clearer.

还可以使用析构函数来确保如果有人忘记调用 Dispose 或将对象包装在 using 块中,非托管资源(目录)被正确清理.

You could also use a destructor to make sure that if someone forgets to call Dispose or wrap the object in a using block that the unmanaged resource (the directory) gets cleaned up properly.

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,因为垃圾收集器将为您处理取消分配内存.

There is no need to manually set objects to null as the garbage collector will handle de-allocating the memory for you.

这篇关于失去参数值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆