2016-12-27 55 views
2

我有小帮手类。这些类在内部用于确保某些类型的字符串始终具有适当的格式(邮件地址,电话号码,ID,URL,键,颜色...)。IDisposable - 在没有外部引用的情况下在类中处理什么?

我希望把它们变成使用块,要能够回收的变量名:

using(Id id = ids.First()) 
{ 
    Container container = containers.getById(id); 
    ... 
} 
foreach(Id id in ids.Skip(1)) 
{ 
    Container container = containers.getById(id); 
    ... 
} 

当我这样做时,Visual Studio问我这些类标记为Disposable,我做到了,但我我不知道如何处理方法存根。让我们来“邮件地址”类为例:

public class MailAddress : IEquatable<MailAddress>, IDisposable 
{ 
    const string MAILADDRESSPATTERN = ... 
    protected string _address; 
    public MailAddress(string address) 
    { 
     if (address == null) throw new ArgumentNullException("address"); 
     if (!Regex.IsMatch(address, MAILADDRESSPATTERN)) throw new ArgumentException("address"); 
     this._address = address.ToLower(); 
    } 

    bool IEquatable<MailAddress>.Equals(MailAddress other) 
    ... 
    public override int GetHashCode() 
    ... 
    ... 
    ... 
    public override string ToString() 
    ... 

    public void Dispose() 
    { 
     throw new NotImplementedException(); 
    } 
} 

究竟会在Dispose功能有这样一类呢?我必须处理哪些垃圾收集器会自动执行哪些操作?

到目前为止,我没有在任何地方给那个班级打电话Dispose,而且它似乎工作正常。现在,该班级是Disposable,我是否必须在整个代码中添加对Dispose的呼叫?

+0

如果你的类没有使用非托管资源,那么'IDisposable'没有用处。 –

+0

垃圾收集器仅处理受管资源。你只需要实现IDisposable你的类正在使用非托管资源,如COM对象。 using语句处理为您处置的呼叫。 –

回答

3

您的Dispose方法毫无用处,因为您似乎没有任何非托管资源。 Dispose仅在您希望手动处理这些资源的情况下有用。

所有托管资源都由GC垃圾收集,因此不需要任何操作。删除班上的IDisposable似乎是合适的操作。这将需要删除的无用using过,你可以换取简单的括号:

{ 
    Id id = ids.First(); 
    Container container = containers.getById(id); 
    ... 
} 
+0

更确切地说'Dispose'对托管对象也有意义:'Dispose'方法释放耗费大量内存的管理对象,或者比垃圾回收器非确定性回收更快消耗稀缺资源。 (https://msdn.microsoft.com/en-us/library/fs2xkftw(v=vs.110).aspx) – Zharro

+0

好的,这也是一个很好的场景。 –

+0

@PatrickHofman要说“Dispose只在你想手动处理非托管资源的情况下有用”是不正确的和误导性的。现在在非托管资源周围实施封装是相当罕见的。通常会使用IDisposable来控制受管资源的及时发布。例如,MySocket.Dispose控制及时发布托管的底层套接字,以便用户可以控制端口关闭的时间(不是IF)。 – Ricibob

5

编译器强制您在Id类中实现IDiposable接口,因为您在using中使用它。 using的唯一目的是在您离开该区块后致电IDisposable.Dispose。所以你只能在IDisposable的实现中使用它。

IDisposable的用途是在对象不再使用时清理外部资源。这包括关闭文件,从数据库断开连接,返回窗口句柄等等。

由于您似乎没有进行清理,因此您不需要using声明。在这种情况下,当你使用using(例如你正在使用不同类型的对象,其中一些具有外部资源的一种方法),你还是要落实Dispose方法来满足接口,但你可以让它空。

如果你的班级是一次性的,你确实应该在你不再需要时处置它,即使Dispose什么都不做。如果您或其他人稍后将清理代码添加到Dispose,则应该依靠它被执行。

6

不这样做,你在滥用语言和Disposable接口/模式。

IDisposable是有非常特殊的原因,其中有非托管资源,或当你的类拥有一次性引用的确定性释放。

这当然不是创建局部范围的手段,因此您可以重用变量名称。如果你需要做的是简单地做:

{ 
    Id id = ids.First()) 
    Container container = containers.getById(id); 
    ... 
} 
+0

他为什么滥用这种语言? –

+0

@PatrickHofman使用'using'来创建本地范围? – InBetween

+0

没关系,明白你的意思。简单的括号也可以完成这项工作。 –

1

不知道为什么你正在使用的using关键字。当执行离开using的范围时,using关键字会对Dispose()进行调用。因此,using括号内的对象必须是IDisposable。如果您没有任何资源需要清理,则无需将对象包装在using中。由于在.net中使用析构函数并不是一个好主意,因此您将放入析构函数的逻辑通常放在Dispose()方法中。当与关键字using结合使用时,可以实现受控的资源管理。

相关问题