如何在using子句中将结构作为ref传递?

时间:2013-07-09 05:31:05

标签: c# struct ref

这就是我想要做的事情:

using(var bmp = Surface.FromBmp("smile.bmp"))
{
    tex = Texture.FromSurface(ref rend, ref bmp);
}

Surfacestruct。我想避免复制结构只是为了将它传递给Texture.FromSurface,所以我将它作为ref传递,即使它没有被修改。 C#没有const-refs的概念,所以我不确定我还能做什么。有没有优雅的解决方案?

我找到了Jon Skeet's answer,但它并没有真正提供解决方案。

2 个答案:

答案 0 :(得分:1)

您可以手动编写相同的代码using using (try/finally)。类似的东西:

IDisposable toClose = null;
try 
{
    var bmp = Surface.FromBmp("smile.bmp"));
    toClose = bmp;
    tex = Texture.FromSurface(ref rend, ref bmp);
}
finally 
{
    toClose.Dispose();
}

答案 1 :(得分:1)

唯一一个“struct-ness”会成为问题的类型是bmp;你是说这是一个结构吗?如果是这样,结构将实现一个非平凡的IDisposable.Dispose()方法似乎非常不寻常,但是该类型可能实现为“不可变”结构,但封装了一个可变引用,其行为类似于一个。在这种情况下,我建议像:

var bmp = Surface.FromBmp("smile.bmp");
try
{
  tex = Texture.FromSurface(ref rend, ref bmp);
}
bmp.Dispose(); // Or whatever method it exposes for such purpose

如果有问题的类型实际上需要处理,它应该为此目的公开一个方法(某些结构类型,如List<T>.Enumerator实现IDisposable因为它们需要实现接口,而不是因为实例需要清理)。不要强制转换为IDisposable,因为这会创建一个新的盒装结构实例;其成本将大大超过创建另一个结构实例的成本。您可以使用的另一种模式是:

var bmp = Surface.FromBmp("smile.bmp");
using(bmp)
{
  tex = Texture.FromSurface(ref rend, ref bmp);
}

因为我认为using语句的形式创建了自己的参数的私有副本,并且可以让你用原文做你喜欢的事情,但是没有必要让代码生成代码的真正原因bmp的额外副本,所以我不会特别推荐这种形式。如果由于某种原因bmp需要清理但除了通过IDisposable之外没有为此目的公开任何方法,您可以执行以下操作:

void CallDisposeOnRef<T>(ref T it) where T:IDisposable { it.Dispose(); }

并用CallDisposeOnRef(ref bmp);替换我的第一个示例的最后一行,这样可以避免以任何方式制作bmp的额外副本(名称很详细,以明确它只有在目标上调用Dispose;有些人可能会期望这样一种方法,即ref参数也将其参数设置为null