Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/drupal/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 确定IDisposable是应该扩展接口还是应该在实现所述接口的类上实现_C#_Dispose_Idisposable - Fatal编程技术网

C# 确定IDisposable是应该扩展接口还是应该在实现所述接口的类上实现

C# 确定IDisposable是应该扩展接口还是应该在实现所述接口的类上实现,c#,dispose,idisposable,C#,Dispose,Idisposable,如何确定是应该使用IDisposable扩展某个接口,还是应该在实现接口的类上实现IDisposable 我有一个接口,除了一个特定的实现之外,它不需要处理任何外部资源。我的选择似乎是: 1) 在要求所有实现实现Dispose的接口上实现IDisposable,即使只有一个空方法 -或- 2) 仅在具有需要处置的资源的类上实现IDisposable。这将导致“使用”出现问题,因为我的对象是从工厂创建的,因此所有上游代码都是针对接口工作的。由于接口未绑定到IDisposable,“使用”不会看到D

如何确定是应该使用IDisposable扩展某个接口,还是应该在实现接口的类上实现IDisposable

我有一个接口,除了一个特定的实现之外,它不需要处理任何外部资源。我的选择似乎是:

1) 在要求所有实现实现Dispose的接口上实现IDisposable,即使只有一个空方法

-或-

2) 仅在具有需要处置的资源的类上实现IDisposable。这将导致“使用”出现问题,因为我的对象是从工厂创建的,因此所有上游代码都是针对接口工作的。由于接口未绑定到IDisposable,“使用”不会看到Dispose方法。然而,我可以将工厂结果用于实施;然而,这会使消费者意识到实现,从而破坏接口的用途


关于最佳实践有什么想法吗?

如果您希望调用方只能与接口交互,而不能与实现交互,那么您希望接口扩展
IDisposable
。如果没有,他们将需要检查
值是否可识别
,以查看是否需要处理它

如果负责处理对象的对象知道具体的实现,并且它仅是被引用的对象(但不负责处理它),那么使用第二个选项。 第一个选项的一个很好的例子是

IEnumerator
。许多
IEnumerator
对象在被释放时不需要做任何事情,但有些则需要,因此接口扩展了
IDisposable
,因为负责该对象的创建/生命周期的对象将(或应该)永远不知道底层实现


第二个示例类似于
IComparer
许多需要比较的对象都是一次性的,但是通过接口使用对象的代码部分并不负责对象的创建/生命周期,因此,它不需要知道该类型是否是一次性的。

50000美元的问题是,处置责任是否会随接口一起传递,或者换句话说,最后一个使用实现对象的实体是否可能是创建它的实体之外的其他实体

IEnumerator
实现
IDisposable
的主要原因是,实现对象是由实现
IEnumerable.GetEnumerator()
的对象创建的,但随后通常被其他对象使用。实现
IEnumerable
的对象将知道它返回的东西是否真的需要处理,但无法知道接收者何时处理完它。调用
IEnumerable.GetEnumerator()
的代码将知道何时处理完返回的对象,但无法知道是否需要进行任何清理。明智的做法是指定需要调用
IEnumerable.GetEnumerator()
的代码,以确保在放弃返回的对象之前对其调用
Dispose
;在许多情况下,
Dispose
方法不会做任何事情,但是无条件调用保证存在的不做任何事情的方法要比检查不存在的方法的存在性便宜


如果接口类型的性质是,实现对象是否需要清理以及何时应该进行清理的问题将由同一实体负责,那么接口就不需要继承
IDisposable
。如果实例将由一个实体创建,但最后由另一个实体使用,那么继承
IDisposable
将是明智的。

如果您在具体类上实现
IDisposable
,并且接口用户知道它可能是一次性的;你能行

IFoo foo = Factory.Create("type");
using(foo as IDisposable){
    foo.bar();
}
如果
foo
未实现
IDisposable
,则
使用
将相当于
使用(null)
,这将正常工作

下面示例程序的输出将是

Fizz.Bar
Fizz.Dispose
Buzz.Bar
示例程序

using System;

internal interface IFoo
{
    void Bar();
}
internal class Fizz : IFoo, IDisposable
{
    public void Dispose()
    {
        Console.WriteLine("Fizz.Dispose");
    }

    public void Bar()
    {
        Console.WriteLine("Fizz.Bar");
    }
}
internal class Buzz : IFoo
{
    public void Bar()
    {
        Console.WriteLine("Buzz.Bar");
    }
}

internal static class Factory
{
    public static IFoo Create(string type)
    {
        switch (type)
        {
            case "fizz":
                return new Fizz();
            case "buzz":
                return new Buzz();
        }
        return null;
    }
}

public class Program
{

    public static void Main(string[] args)
    {

        IFoo fizz = Factory.Create("fizz");
        IFoo buzz = Factory.Create("buzz");

        using (fizz as IDisposable)
        {
            fizz.Bar();
        }
        using (buzz as IDisposable)
        {
            buzz.Bar();
        }
        Console.ReadLine();
    }

}

如果您希望您的界面支持
使用
,那么第一个选项是唯一的选项。毕竟,所有代码都是针对接口本身编写的,而不是针对特定的实现。而“Dispose”的noop实现可能是多余的,但它是在一秒钟内实现的。