从c#中继承结构的梦想

时间:2012-06-16 17:42:45

标签: c# inheritance struct xna xna-4.0

我正在使用C#XNA 4.0制作2D游戏,并再次遇到我的小烦恼; 矩形。对于那些使用基本碰撞的人来说,这几乎是必需的。对于几乎所有创建的游戏对象,您都需要有一个矩形。然后我去改变X,检查碰撞或其他任何东西。在那里,我开始了objectName.Rectangle.Whatever的永无止境的战斗。为了解决这个问题,我当然会给出一些objectName属性/方法来为我访问这些属性/方法。

然后我敢于梦想。我有一个伟大的设计来制作一个基本的游戏对象类,所有drawable将继承,这将允许父母,精确的本地坐标(浮点数),并保持纹理/ spritebatch。为了完成这个,我准备从Rectangle继承,使用它拥有的所有方法和属性。哎呀,每当需要一个Rectangle的东西时,我可能会懒得说objectName,而不是objectName.Rectangle。

然后我意识到,不是机会。我开始感到沮丧,因为我很聪明的想法被砸碎了。从那以后,我完美的小班级拥有一个矩形,各种方法和属性根据需要访问它。我也有机会从XNA DrawableGameComponent继承它。虽然从长远来看这更实用,每次我查看绘制或更新方法并看到我经常想到的矩形调用时,是否有希望做我想要的事情?我可以做一些聪明的工作吗?或者是从一个真正被我掌握的矩形继承而来?

虽然使用XNA中提供的DrawableGameComponent类允许大多数与游戏对象相关的操作发生在Update()方法类中,但每次在类之外我都需要引用不是Rectangle的属性,而是Rectangle本身,考虑到我的对象实际上是每个方式,并且加强了Rectangle,我感到有点恼怒。然后我再次发现自己在问:

有没有办法从预定义的结构继承,或者给项目留下你的印象(解决方法)?

3 个答案:

答案 0 :(得分:16)

继承否,但您可以使用扩展方法向Rectangle对象添加许多“默认”功能。 例如

  //(inside a static class)
  public static int GetSurface(this Rectangle rect){return rect.Width * rect.Height;}

  //calling
  Rectangle rect;
  var s = rect.GetSurface();

那就是说,我通常做的是封装所说的结构。使用该类作为基础对象,并添加一个运算符,以便可以将其隐式转换为Rectangle。这样它就可以传递给一个需要一个矩形而不需要强制转换的方法。

    public class MyRect //class so you can inherit from it, but you could make your own struct as well
    {
        public int X { get; set; }
        public int Y { get; set; }
        public int Width { get; set; }
        public int Height { get; set; }
        public int Right { get { return X + Width; } }
        public int Bottom{ get { return Y + Height; } }

        public static implicit operator Rectangle(MyRect rect)
        {
            return new Rectangle(rect.X, rect.Y, rect.Width, rect.Height);
        }

        public static implicit operator MyRect(Rectangle rect)
        {
            return new MyRect { X = rect.X, Y = rect.Y, Width = rect.Width, Height = rect.Height };
        }

    }       
 }

现在,您可以手动创建自己的矩形,也可以从现有的矩形创建:

  MyRect rect = ARectangleVar

你可以在遗留方法中使用它,期望一个没有强制转换的矩形

答案 1 :(得分:4)

这是一个可能的解决方法(把它放在MyClass中,你所说的具有Rectangle属性的类):

public static implicit operator Rectangle(MyClass obj)
{
    return obj.Rectangle;
}

这将是,例如允许您将对象传递给期望Rectangle的方法,并且它可以正常工作。请注意,与真正的继承不同,存在的Rectangle与您传入的MyClass的实例不同,它只是一个由该值构成的结构。

答案 2 :(得分:0)

值类型从根本上与适用于类类型的继承风格不兼容,但是能够以编译器识别双向身份保留转换的方式声明“派生结构”将是有帮助的。派生类型和原始类型之间。派生结构将需要只有一个字段,称为“Base”(尽管C#编译器可以接受关键字base作为替代),其类型是派生的结构的类型。名称与周围类型不匹配的“Base”的所有成员将被视为封闭结构的成员。

“派生结构”提供的主要内容,但目前缺乏的主要内容是:

  1. 能够访问包装结构的成员而无需添加额外的语法间接层。例如,如果有一个实例`MyFancyPoint`是从`Point`中剔除的类型,可以说`MyFancyPoint.X + = 5`而不是'MyFancyPoint.Base.X + = 5`。
  2. 一次执行多个隐式或显式类型转换的功能。 C#通常只允许从“X”转换为“Y”,除非存在直接转换,部分原因是搜索所有可能的转换序列很困难,部分原因是这样做通常会产生关于转换序列的模糊性应该受雇。如果假设包装特定结构的所有类型都表示具有保留标识的突变的“云”,则两个派生结构“XX:X”和“YY:Y”之间的转换可以毫不含糊地视为转换为“X”。 ,然后是“Y”,然后是“YY”(如果存在“X”到“Y”转换,那将是合法的)。
  3. 将ByRef作为ByRef的一个类型的实例视为另一个的实例,将ByRef视为一个字段的ByRef被视为另一个的相应字段的ByRef。

我不确定是否需要对运行时进行任何更改以支持任何这些功能,如果接受盒装派生类型的项目可能只是作为相同的派生类型而被取消装箱;允许将框架版本的结构直接转换为身份可转换派生的实例,这将有所帮助,但可能会增加复杂性。我不确定是否需要这样的行为来使泛型工作。 不幸的是,我觉得许多负责做出这种决定的人真的不喜欢价值类型。由于.net历史早期的一些设计决策(特别是缺少“const ref”参数和通过ref公开属性的方法),使结构以语义正确的方式工作可能是一个挑战,并且我认为有些实现者宁愿使用结构的问题作为改进.net处理它们的借口,而不是添加可以解决问题的功能。