简体   繁体   English

识别 Visual Studio 中的一次性对象?

[英]Recognize Disposable Objects in Visual Studio?

It is suggested that IDisposable objects should be disposed in either using statement or by calling Dispose() method.建议在using语句或调用Dispose()方法中处理IDisposable对象。 I find it is not intuitive to find out if an object is disposable in Visual Studio.我发现在 Visual Studio 中确定 object 是否是一次性的并不直观。

My question is: is there any way to recognize IDisposable objects in VS?我的问题是:有什么方法可以识别 VS 中的IDisposable对象吗?

If you want to highlight disposable objects differently in VS please check out this post . 如果您想在VS中以不同方式突出显示一次性物体,请查看此文章 I personally prefer Resharper answer as I always use R#. 我个人更喜欢Resharper的回答,因为我总是使用R#。

If you just want to figure out if your object is an instance of some interface you can right-button-click on the variable name and Navigate -> Object Browser or Go to Declaration and then right-button-click on class name Go to Definition / Peek Definition . 如果您只想弄清楚您的对象是否是某个界面的实例,您可以右键单击变量名称并Navigate -> Object BrowserGo to Declaration ,然后右键单击类名Go to Definition / Peek Definition

在此输入图像描述

You might like Peek Definition as it shows everything you need inline: 您可能喜欢Peek Definition因为它显示了您需要内联的所有内容:

在此输入图像描述

You can always check what methods object has, if it has Dispose() method then 99.9% it's a disposable object. 您可以随时检查对象具有哪些方法,如果它具有Dispose()方法,则99.9%它是一次性对象。 I'll give this 0.01% for those who give methods bad names :). 对于那些给方法不好的人:)我会给这个0.01%。

I'm surprised that no-one else has mentioned this yet. 我很惊讶没有人提到过这个。 If your edition of Visual Studio supports it, I'd suggest turning on Code Analysis for Build. 如果您的Visual Studio版本支持它,我建议启用Code Analysis for Build。

Once that's done, pick whatever rule sets you like so long as they ensure that, at the least, CA2000 (Dispose objects before losing scope), CA2213 (Disposable fields should be disposed) and CA2202 (Do not dispose objects multiple times) rules are covered. 完成后,选择您喜欢的任何规则集,只要它们确保至少CA2000 (丢失范围之前丢弃对象), CA2213 (应丢弃一次性字段)和CA2202 (不要多次丢弃对象)规则是覆盖。 That way, the compiler should shout at you if you're not dealing with disposable objects correctly. 这样,如果您没有正确处理一次性对象,编译器应该对您大喊大叫

(Although note that getting the compiler to not flag some usage of disposable objects can then turn into the bigger challenge, as many StackOverflow questions can attest) (尽管注意到让编译器标记一次性对象的某些用法然后会变成更大的挑战,因为许多StackOverflow问题可以证明)

You can use Object Browser to view class inheritance hierarchy with implemented interfaces 您可以使用对象浏览器查看已实现接口的类继承层次结构

在此输入图像描述

For the sake of completeness, if you don't ask how to check it in your code but you just want to know where you can look if the type implements an interface like IDisposable , you can always look at MSDN . 为了完整起见,如果你不问如何在你的代码中检查它,但你只想知道如果类型实现了像IDisposable这样的接口你可以在哪里看,你可以随时查看MSDN

For example FileStream 例如FileStream

  • it's already mentioned in the remarks section: 它已经在备注部分提到:

This type implements the IDisposable interface. 此类型实现IDisposable接口。 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. 要直接处理类型,请在try / catch块中调用其Dispose方法。 To dispose of it indirectly, use a language construct such as using (in C#) or Using (in Visual Basic). 要间接处理它,请使用语言构造,例如使用(在C#中)或使用(在Visual Basic中)。 For more information, see the “Using an Object that Implements IDisposable” section in the IDisposable interface topic. 有关更多信息,请参阅IDisposable接口主题中的“使用实现IDisposable的对象”部分。

  • or search for the Dispose method . 或搜索Dispose方法 There you can see if this class or any parent class implements IDispable . 在那里,您可以看到此类或任何父类是否实现了IDispable In this case it is inherited from Stream which implements that interface which is mentioned at the class syntax and in the remarks section. 在这种情况下,它继承自Stream ,它实现了在类语法和备注部分中提到的接口。

     public abstract class Stream : MarshalByRefObject, IDisposable 

If you want to know how to find implementations of an interface in Visual Studio , here is already a question that answers that: 如果您想知道如何在Visual Studio中查找接口的实现,这里已经有一个问题可以解答:

How do you find all implementations of an interface? 你如何找到界面的所有实现?

A way to see what interfaces a class implements, along with all of it's publicly exposed fields, properties, methods etc. is to go to that class in the code. 查看类实现的接口以及所有公开的字段,属性,方法等的方法是在代码中转到该类。 For example: 例如:

Image image = Image.FromFile(path);

Make sure you click on the class, not the instance and press F12. 确保单击该类,而不是实例,然后按F12。 This will take you to a metadata file for that class. 这将带您进入该类的元数据文件。 For example: the Image.cs file has the following above class declaration: 例如: Image.cs文件具有以下类声明:

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

You can then also use F12 to click through to other classes. 然后,您还可以使用F12单击其他类。 Note that these classes are usually shown up in the Light Blue colour in Visual Studio: 请注意,这些类通常在Visual Studio中以浅蓝色显示:

屏幕截图显示浅蓝色。

You can also get to this meta data file by right clicking on the class and selecting "Go To Definition" from the drop down list. 您还可以通过右键单击该类并从下拉列表中选择“转到定义”来获取此元数据文件。


Though not ideal you can also go to an instance of the class and put a . 虽然不理想,但你也可以去一个班级的实例,然后放一个. on the end. 最后。 This should bring up the intellisense and you will be able to see Dispsose() in the list if the item implements the interface. 这应该调出intellisense,如果项目实现了接口,你将能够在列表中看到Dispsose()

You could also just write myInstance.Dispose(); 你也可以写myInstance.Dispose(); or using (myInstance = new MyClass()) {} and if it compiles the class implements the interface else it doesn't. using (myInstance = new MyClass()) {}如果它编译该类实现接口,否则它不会。

As a (silly?) alternative to shelling out for Resharper and its ilk, Visual Studio does have the concept of External Tools (in the Tools menu), which you could (ab)use to do something like: 作为对Resharper及其同类产品进行炮轰的(愚蠢?)替代方案,Visual Studio确实具有外部工具 (在“工具”菜单中)的概念,您可以(ab)使用它来执行以下操作:

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

This would read whatever string you had selected in the editor, search for .NET types with that string as a name and show a True/False as to whether that string implemented IDisposable. 这将读取您在编辑器中选择的任何字符串,搜索具有该字符串作为名称的.NET类型,并显示该字符串是否实现IDisposable的True / False。

The Powershell command in the tool is just the quickest approach I could do to demonstrate the possibility, but it is far from perfect -- it only finds types in assemblies that Powershell loads by default. 该工具中的Powershell命令只是我可以用来证明这种可能性的最快方法,但它远非完美 - 它只能在Powershell默认加载的程序集中找到类型。 If you wanted to expand on the idea, you could build a command-line .NET app that loaded your project and scanned all the assemblies that your project loaded. 如果您想扩展这个想法,可以构建一个命令行.NET应用程序来加载项目并扫描项目加载的所有程序集。

If you highlighted the word Stream in your code, for example, and ran your external tool ( ALT + T , ALT + B in the example), it would return: 例如,如果您在代码中突出显示了单词Stream ,并运行了外部工具(示例中为ALT + TALT + B ),则会返回:

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

To break down the Powershell command: 要分解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

Easiest way to find out this is by using memory warning in Code Analysis.找出这一点的最简单方法是使用代码分析中的 memory 警告。

  1. Enable Code Analysis to "Run on build" on project properties.启用代码分析以在项目属性上“在生成时运行”。 在此处输入图像描述

  2. Look for following warnings after build构建后寻找以下警告

CA2000 CA2000

A local object of an IDisposable type is created, but the object is not disposed before all references to the object are out of scope.创建了 IDisposable 类型的本地 object,但在对 object 的所有引用都从 scope 中移除之前,object 未被释放。

CA2213 CA2213

A type that implements System.IDisposable declares fields that are of types that also implement IDisposable.实现 System.IDisposable 的类型声明的字段也是实现 IDisposable 的类型。 The Dispose method of the field is not called by the Dispose method of the declaring type.声明类型的 Dispose 方法未调用字段的 Dispose 方法。

在此处输入图像描述

either using or in Dispose() method Use the using construct when you can. either using or in Dispose() method使用using构造。 Here's why. 这就是原因。 Using this MSDN example, here are two equivalent blocks of code. 使用此MSDN示例,这里有两个等效的代码块。 This one with using : 这一个using

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

This one without using : 这一个没有using

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

Each part of the second block is there for a reason: the curly braces, the try-finally, the null check, and the cast to IDisposable. 第二个块的每个部分都有一个原因:花括号,try-finally,null检查和强制转换为IDisposable。 No one should be expected to remember this. 不应该让人记住这一点。 That's why the using construct exists. 这就是using构造存在的原因。

Something clean that can be done in C#7 可以在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 could be some virtual or abstract function. Fooy可能是一些虚拟抽象的功能。 Some base classes may implement IDisposable while others not. 一些基类可以实现IDisposable而其他基类不实现。 Try running the above code. 尝试运行上面的代码。 The console will print different text depending whether or not IDisposable has been implemented 控制台将根据是否已实现IDisposable打印不同的文本

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM