认识 Visual Studio 中的一次性物品?

Recognize Disposable Objects in Visual Studio?

建议 IDisposable 个对象应该在 using 语句中或通过调用 Dispose() 方法来处理。我发现在 Visual Studio.

中找出一个对象是否是一次性的并不直观

我的问题是:有没有办法在 VS 中识别 IDisposable 对象?

如果你想在 VS 中以不同方式突出显示一次性对象,请查看此 post. I personally prefer Resharper answer 因为我一直使用 R#。

如果你只是想弄清楚你的对象是否是某个接口的实例,你可以右键单击变量名和 Navigate -> Object BrowserGo to Declaration 然后右键-单击 class 名称 Go to Definition/Peek Definition.

您可能会喜欢 Peek Definition,因为它内联显示了您需要的所有内容:

你总是可以检查对象有哪些方法,如果它有 Dispose() 方法那么 99.9% 它是一次性对象。我会给那些给方法起坏名字的人 0.01%:).

为了完整起见,如果你不问如何在你的代码中检查它,而只是想知道你可以在哪里查看类型是否实现了像 IDisposable 这样的接口,你总是可以看看 MSDN.

例如FileStream

  • 已经在备注部分提到了:

This type implements the IDisposable interface. When you have finished using the type, you should dispose of it either directly or indirectly. To dispose of the type directly, call its Dispose method in a try/catch block. To dispose of it indirectly, use a language construct such as using (in C#) or Using (in Visual Basic). For more information, see the “Using an Object that Implements IDisposable” section in the IDisposable interface topic.

  • 或搜索实现 class 语法和备注部分中提到的接口的 Dispose method. There you can see if this class or any parent class implements IDispable. In this case it is inherited from Stream

    public abstract class Stream : MarshalByRefObject, IDisposable
    

如果您想知道如何在 Visual Studio 中找到接口的实现,这里已经有一个问题可以回答:

How do you find all implementations of an interface?

您可以使用对象浏览器查看 class 具有已实现接口的继承层次结构

查看 class 实现的接口及其所有公开字段、属性、方法等的一种方法是转到代码中的 class。例如:

Image image = Image.FromFile(path);

确保单击 class,而不是实例,然后按 F12。这会将您带到该 class 的元数据文件。例如:Image.cs 文件有以下 class 声明:

public abstract class Image : MarshalByRefObject, ISerializable, ICloneable, IDisposable

然后您还可以使用 F12 点击进入其他 classes。请注意,这些 classes 通常以浅蓝色显示在 Visual Studio:

您还可以通过右键单击 class 并从下拉列表中选择 "Go To Definition" 来访问此元数据文件。


虽然不理想,但您也可以转到 class 的实例并在末尾放置一个 .。这应该会调出智能感知,如果该项目实现了接口,您将能够在列表中看到 Dispsose()

您也可以只编写 myInstance.Dispose();using (myInstance = new MyClass()) {},如果它编译 class 实现接口,否则它不会。

可以在 C#7 中完成的干净的东西

class Foo : IDisposable {
    string _bar = "init";
    void Fooy() { _bar = "fooy"; }

    public void Dispose() {
        _bar = null;       
    }

    static void Main()
    {
        var v = new Foo();
        Console.WriteLine(v._bar);
        if(v is IDisposable id) using(id)
            v.Fooy();
        else
            v.Fooy();

        Console.WriteLine(v._bar ?? "null");;

    }
}

Fooy 可能是一些 virtualabstract 函数。一些基础 类 可能会实现 IDisposable 而另一些则不会。尝试 运行 上面的代码。控制台将根据 IDisposable 是否已实施

打印不同的文本

either using or in Dispose() method 尽可能使用 using 结构。这就是为什么。使用此 MSDN 示例,这里有两个等效的代码块。这个 using:

using (Font font1 = new Font("Arial", 10.0f)) 
{
    byte charset = font1.GdiCharSet;
}

这个没有using:

{
    Font font1 = new Font("Arial", 10.0f);
    try
    {
        byte charset = font1.GdiCharSet;
    }
    finally
    {
        if (font1 != null)
            ((IDisposable)font1).Dispose();
    }
}

第二个块的每个部分都是有原因的:花括号、try-finally、null 检查和转换为 IDisposable。没有人应该记住这一点。这就是 using 构造存在的原因。

作为 Resharper 及其同类产品的(愚蠢的?)替代品,Visual Studio 确实具有 外部工具 的概念(在“工具”菜单中),您可以(ab)使用它来做类似的事情:

  • 标题: Is Disposa&ble
  • 命令: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
  • 参数: -Command "&{$i=[Type]::GetType('System.IDisposable');[AppDomain]::CurrentDomain.GetAssemblies()|%{ $_.GetTypes()}|?{$_.FullName.EndsWith('.$(CurText)')}|%{New-Object PSObject -Property @{'Type'=$_;'IDisposable'=$i.IsAssignableFrom($_)}}|ft}"
  • 使用输出 window: 选中

这将读取您在编辑器中选择的任何字符串,搜索以该字符串作为名称的 .NET 类型,并显示 True/False 关于该字符串是否实现了 IDisposable。

该工具中的 Powershell 命令只是我可以用来证明这种可能性的最快 方法,但它远非完美——它只能在 Powershell 可以找到的程序集中找到类型默认加载。如果您想扩展这个想法,您可以构建一个 command-line .NET 应用程序来加载您的项目并扫描您的项目加载的所有程序集。

如果您在代码中突出显示 Stream 一词,并且 运行 您的外部工具 (ALT+T ,ALT+B),它会 return:

Type             IDisposable
----             -----------
System.IO.Stream        True

分解 Powershell 命令:

&{ $i=[Type]::GetType('System.IDisposable');        # Get the IDisposable interface
   [AppDomain]::CurrentDomain.GetAssemblies() `     # Get all loaded assemblies
    | %{ $_.GetTypes() } `                          # For each assembly, get all types
    | ?{ $_.FullName.EndsWith('.$(CurText)') } `    # Filter types that are named $(CurText) - $(CurText) is a macro within VS External Tools
    | %{ New-Object PSObject -Property @{           # For each type, return an object containing...
         'Type' = $_;                               # ...the type name...
         'IDisposable' = $i.IsAssignableFrom($_)    # ...and whether the IDisposable interface is implemented
       } } `
    | ft }                                          # Format all returned objects as a table

令我惊讶的是,还没有其他人提到这一点。如果您的 edition of Visual Studio supports it, I'd suggest turning on Code Analysis 用于 Build.

完成后,选择您喜欢的任何规则集,只要它们确保至少包含 CA2000 (Dispose objects before losing scope), CA2213 (Disposable fields should be disposed) and CA2202(不要多次处理对象)规则即可。这样,如果您没有正确处理一次性对象,编译器应该对您大喊大叫

(尽管请注意,让编译器 而不是 标记一些一次性对象的使用可能会变成更大的挑战,正如许多 Whosebug 问题可以证明的那样)