如何在 using 子句中将结构作为引用传递

本文关键字:引用 结构 using 子句 | 更新日期: 2023-09-27 18:21:46

这就是我想做的:

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

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

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

如何在 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();
}

唯一"结构性"有问题的类型是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 (