【问题标题】:Pass `List<List<Bitmap>>` as ref将 `List<List<Bitmap>>` 作为 ref 传递
【发布时间】:2012-04-03 17:39:41
【问题描述】:

我正在用 C# 制作 Space Invaders 游戏,使用 Bitmap 存储入侵者、炸弹等的图像。
让我困惑的是:
我有一个抽象类GameObject 代表游戏中的简单元素:

protected Bitmap image;
protected Rectangle bounds;
protected Rectangle movementBounds;

public GameObject(ref Bitmap image, Point position, Rectangle movementBounds)
{
    this.image = image;
    this.bounds = new Rectangle(position, new Size(image.Width, image.Height));
    this.movementBounds = movementBounds;
}

比代表Shield 的单个正方形的ShieldSegment 类,它有四个不同阶段损坏的图像:

private int timesHit = 0;
private IList<Bitmap> alternateImages = new List<Bitmap>();

public ShieldSegment(ref List<Bitmap> images, Point position, Rectangle movementBounds)
    : base(ref images.First(), position, movementBounds)
{
    alternateImages = images;
}

还有一个Shield 类,它将整个盾牌表示为一个段列表:

private IList<ShieldSegment> segments = new List<ShieldSegment>();

//fill, upper left, upper right, lower left, lower right
public Shield(ref List<List<Bitmap>> images, Point position, Size imageSize)
{
    //upper row
    Point startPosition = position;
    segments.Add(new ShieldSegment(ref images.ElementAt(1), startPosition,new Rectangle(startPosition, imageSize)));
    startPosition.X += imageSize.Width;
    segments.Add(new ShieldSegment(ref images.ElementAt(0), startPosition,new Rectangle(startPosition, imageSize)));
    startPosition.X += imageSize.Width;
    segments.Add(new ShieldSegment(ref images.ElementAt(0), startPosition, new Rectangle(startPosition, imageSize)));
    startPosition.X += imageSize.Width;
    segments.Add(new ShieldSegment(ref images.ElementAt(2), startPosition, new Rectangle(startPosition, imageSize)));
    //middle row
    startPosition = position;
    startPosition.Y += imageSize.Height;
...

我需要将列表元素作为引用传递,因为(如果我错了,很抱歉)为每个段和盾牌重新存储图像会很浪费。将单个引用传递给Bitmap 时它工作正常,但在这里我得到a ref or out argument must be an assignable variable
有什么办法吗?

【问题讨论】:

    标签: c# list ref


    【解决方案1】:

    我需要将列表元素作为引用传递

    你在这里不是很清楚。列表引用只是传递,默认情况下按值传递,但必要时通过引用传递。当您访问该列表时,您将获得一个参考。但是,这段代码:

    public ShieldSegment(ref List<Bitmap> images, Point position, 
         Rectangle movementBounds)
        : base(ref images.First(), position, movementBounds)
    {
        alternateImages = images;
    }
    

    建议您可能不了解 .NET 中参数传递的工作原理:

    • 你没有改变images参数的值,所以你不需要使用ref
    • ref 与作为方法调用结果的参数一起使用是没有意义的……您期望它会做什么?

    我建议你阅读我的article on it,以及我在reference types and value types 上的文章,应该可以澄清一些事情。

    【讨论】:

    • 都是类。我马上去读。还有一点问题 - 我已经启动并运行了游戏,传递了没有 ref 关键字的图像,但我注意到内存使用量上升到大约 80 Mb,这似乎太多了。所以我认为这是因为游戏对象的每个实例都存储了图像的副本。
    • @AlexandarŽivkovič:不,这不是它的工作方式。每个 Game 对象都有一个对 Bitmap 对象的reference。每个对象是否都引用了 same 对象取决于您如何填充它们... 80MB 听起来并不特别巨大,如果你有的话相当多的图形等。
    • 这就是我填充它们的方式:pastebin.com/C8yU6Bh4 开始时有 55 个入侵者,每个有 2 个大约 300 字节的图像,一个坦克(一个图像,相同大小)和 4 个盾牌每个 12 段,每段每 150 字节有 4 个图像。但它看起来仍然很多,尤其是因为它一直在跳跃,具体取决于屏幕上的事物数量。
    【解决方案2】:

    List 是一个引用类型。这意味着List 变量本身的值images 是一个引用。不用ref也可以通过!

    请注意不要将其视为函数中的out 参数。例如,不要用images = new List... 将东西分配给images,那是行不通的。

    【讨论】:

    • 您能详细说明一下吗?如果我从 ShieldSegmentShield 中删除 ref 关键字,则会收到无效参数错误。
    • 您确实从函数定义和函数调用中删除了 ref 关键字,对吧?
    • 是的,在 ShieldShieldSegment 中,但我需要在 GameObject 构造函数中使用它,因为代表坦克、入侵者等的类。
    • 什么? GameObject 构造函数中没有列表。这仍然是关于让列表作为函数参数工作,还是您现在正在尝试解决其他问题?
    • 我的错 - 我已经从 ShieldSegmentShield 中删除了 ref 关键字,但由于其他类,我需要在 GameObject 构造函数 (GameObject(ref Bitmap image, ...) 中使用它。我想我只是稍微改变一下ShieldSegment 的实现,这样它就不会扩展GameObject。我无法在ShieldSegment 中传递images.First(),因为它与GameObject 中的参数不匹配,因为它需要一个引用。
    猜你喜欢
    • 2012-06-28
    • 1970-01-01
    • 1970-01-01
    • 2017-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多