为非托管资源传递构造函数委托或对象

时间:2014-05-20 08:11:46

标签: c# unmanaged idisposable using-statement

在我的(简化)问题中,我有一个方法“阅读”,它可以使用某些IDisposableThing的许多不同实现。我正在将委托传递给构造函数,所以我可以使用using语句。

这种传递我的对象的构造函数的委托的方法是否合适? 我的问题是像List<Func<IDisposable>>等开始看起来有些可怕(因为委托看起来像c#中的废话)并且传入一个对象似乎更常见,更明确的意图陈述。

如果没有代表,是否有更好/不同的方式来管理这种情况?

    public void Main()
    {
        Reading(() => new DisposableThingImplementation());
        Reading(() => new AnotherDisposableThingImplementation());
    }

    public void Reading(Func<IDisposableThing> constructor)
    {
        using (IDisposableThing streamReader = constructor())
        {
            //do things
        }
    }

2 个答案:

答案 0 :(得分:1)

  

这种传递我的对象的构造函数的委托的方法是否合适?我的问题是像List<Func<IDisposable>>等这样的东西开始看起来有点可怕(因为委托看起来像c#中的垃圾)并且传入一个对象似乎更常见,更清晰的意图陈述。

是的,没关系。但是,我理解您对传递这些事物列表的担忧......也许创建一个与Func<IDisposable>具有相同签名的自定义委托,并且更明确的名称(例如SomethingFactory)会更清楚。

  

如果没有代表,是否有更好/不同的方式来管理这种情况?

您可以将工厂或工厂列表传递给方法。不过,我不认为它真的“更好”;它大致相同,因为您的工厂通常会被表示为具有单个方法的接口,这与委托基本相同。

答案 1 :(得分:1)

正如我在评论中所说,很难说出最符合你情况的是什么,所以我只会列出你的选择,以便你做出明智的决定:

继续做你正在做的事

在周围使用具有令人不快的复杂外观类型的物体可能在视觉上并不理想,但在您的情况下它可能是完全合适的

使用自定义委托类型

您可以定义一个委托:

public delegate IDisposableThing DisposableThingConstructor();

然后你可以在任何地方写Func<IDisposableThing>,你可以写DisposableThingConstructor。对于常用的委托类型,这可以提高代码的可读性,尽管这也是一种品味问题。

using语句移出Reading

这实际上取决于对这些对象的生命周期管理是否合理是Reading方法的责任。鉴于我们目前拥有的代码,我们无法真正为您判断。生命周期管理移出的实现看起来像:

public void Main()
{
    using(var disposableThing = new DisposableThingImplementation())
        Reading(disposableThing);
}

public void Reading(IDisposableThing disposableThing)
{
    //do things
}

使用工厂模式

在此选项中,您将创建一个返回新IDisposableThing实现的类。很多信息都可以在你可能已经知道的工厂模式中找到,所以我不会在这里重复一遍。这个选项可能在你的目的上有点过分,增加了许多无意义的复杂性,但是根据这些DisposableThing的构造方式,它可能有额外的好处,使它值得。

使用通用参数

此选项仅在所有IDisposableThing实现都具有无参数构造函数时才有效。我猜不是这样,但如果是的话,这是一个相对简单的方法:

public void Reading<T>() where T : IDisposableThing, new()
{
    using(var disposableThing = new T())
    {
        //do things
    }
}

使用反转控制容器

这是另一种选择,如果单独用于此目的肯定会有点过分。我把它包括在内是为了完整性。像Ninject这样的控制容器的反转将为您提供简单的方法来管理传递给其他人的对象的生命周期。

我非常怀疑在你的情况下这将是一个合适的解决方案,特别是因为一次性对象没有在另一个类的构造函数中使用。如果您后来遇到了一个尝试在更大,更复杂的对象图中管理对象生命周期的情况,那么此选项可能值得重新访问。

构建using语句

之外的对象

这在MSDN documentation中被特别描述为“不是最佳做法”,但它是一种选择。你可以这样做:

public void Main()
{
    Reading(new DisposableThingImplementation());
}

public void Reading(IDisposableThing disposableThing)
{
    using (disposableThing)
    {
        //do things
    }
}

using语句结束时,将调用Dispose方法,但该对象不会被垃圾收集,因为它仍在范围内。在此之后尝试使用该对象很可能会导致问题,因为它未完全初始化。所以,虽然这是一个选择,但它不太可能是一个好选择。