“新”修饰符导致基本实现具有 NULL 属性值
我正在尝试使用多态性让派生类使用派生属性而不是基属性进行操作。我不知道如何用更清晰的语言表达它,所以这里有一个输出示例:
// setup output to demonstrate the scenario
static void Main(string[] args)
{
var foo = new Foo();
var foobase = foo as FooBase;
Console.WriteLine("Foo is null? {0}", foo == null);
Console.WriteLine("Foo.Bar is null? {0}", foo.Bar == null);
Console.WriteLine("FooBase is null? {0}", foobase == null);
Console.WriteLine("FooBase.Bar is null? {0}", foobase.Bar == null);
Console.ReadLine();
}
// base and derived. These represent my problem.
class BarBase { }
class Bar : BarBase { }
// Base implementation using base properties
class FooBase
{
public virtual BarBase Bar { get; set; }
public FooBase() { }
}
// Derived implementation using "new" to operate with the
// derived the property
class Foo : FooBase
{
public new Bar Bar { get; set; }
public Foo() : base()
{
// populate our modified property with the derived class
Bar = new Bar();
//base.Bar = Bar; // I don't want to do this, but how can I avoid it?
}
}
OUTPUT:
Foo is null? False Foo.Bar is null? False FooBase is null? False FooBase.Bar is null? True
问题是“FooBase.Bar”为 NULL。我知道 new 修饰符隐藏了基本实现,这就是为什么我知道我可以通过添加(注释掉)行来使其工作:
base.Bar = Bar; // I don't want to do this, but how can I avoid it?
有更好的方法吗?我缺少什么?
提前致谢!
编辑 (6/7/11)
为我的问题添加一个更具体的示例。基本上,游戏和相机都有抽象实现(这里非常基本......)。抽象 Game 使用抽象 Camera 进行基本工作。派生游戏使用其派生相机来完成其专业工作。最后,我需要派生相机和抽象相机在各自的范围内工作。
我给出了两种不同的相机实现和两种游戏实现来(希望)展示我正在寻找的灵活性。请注意,Game1 使用“hack”来强制基本相机具有值 - Game2 不会执行此操作。 Game1 具有我想要的行为,但没有我想要的实现。
class GameAndCameraExample
{
static void Main(string[] args)
{
new Game1().Play();
Console.WriteLine();
new Game2().Play();
Console.ReadLine();
}
// abstract camera
abstract class CameraBase
{
public void SpecialCameraBaseMethod()
{
Console.WriteLine("SpecialCameraBaseMethod");
}
}
// camera implementation
class ChaseCamera : CameraBase
{
public void SpecialChaseCameraMethod()
{
Console.WriteLine("SpecialChaseCameraMethod");
}
}
// a different camera implementation
class FlightCamera : CameraBase
{
public void SpecialFlightCameraMethod()
{
Console.WriteLine("SpecialFlightCameraMethod");
}
}
// abstract game
abstract class GameBase
{
public virtual CameraBase Camera { get; set; }
public GameBase() { }
public virtual void Play()
{
Console.WriteLine("GameBase.Camera is null? {0}", Camera == null);
if(Camera != null) // it will be null for Game2 :-(
Camera.SpecialCameraBaseMethod();
}
}
// awesome game using chase cameras
class Game1 : GameBase
{
public new ChaseCamera Camera { get; set; }
public Game1() : base()
{
Camera = new ChaseCamera();
base.Camera = Camera; // HACK: How can I avoid this?
}
public override void Play()
{
Console.WriteLine("Game.Camera is null? {0}", Camera == null);
Camera.SpecialChaseCameraMethod();
base.Play();
}
}
// even more awesome game using flight cameras
class Game2 : GameBase
{
public new FlightCamera Camera { get; set; }
public Game2()
: base()
{
Camera = new FlightCamera();
}
public override void Play()
{
Console.WriteLine("Game.Camera is null? {0}", Camera == null);
Camera.SpecialFlightCameraMethod();
base.Play();
}
}
}
输出:
Game.Camera is null? False SpecialChaseCameraMethod GameBase.Camera is null? False SpecialCameraBaseMethod Game.Camera is null? False SpecialFlightCameraMethod GameBase.Camera is null? True
继承是最好的方法吗?
I'm trying to use Polymorphism to have a derived class operate with a derived property instead of the base property. I'm not sure how to put it in clearer words, so here's an example with the output:
// setup output to demonstrate the scenario
static void Main(string[] args)
{
var foo = new Foo();
var foobase = foo as FooBase;
Console.WriteLine("Foo is null? {0}", foo == null);
Console.WriteLine("Foo.Bar is null? {0}", foo.Bar == null);
Console.WriteLine("FooBase is null? {0}", foobase == null);
Console.WriteLine("FooBase.Bar is null? {0}", foobase.Bar == null);
Console.ReadLine();
}
// base and derived. These represent my problem.
class BarBase { }
class Bar : BarBase { }
// Base implementation using base properties
class FooBase
{
public virtual BarBase Bar { get; set; }
public FooBase() { }
}
// Derived implementation using "new" to operate with the
// derived the property
class Foo : FooBase
{
public new Bar Bar { get; set; }
public Foo() : base()
{
// populate our modified property with the derived class
Bar = new Bar();
//base.Bar = Bar; // I don't want to do this, but how can I avoid it?
}
}
OUTPUT:
Foo is null? False Foo.Bar is null? False FooBase is null? False FooBase.Bar is null? True
The problem is "FooBase.Bar" is NULL. I understand that the new modifier is hiding the base implementation, that's why I know I can make it work by adding the (commented out) line:
base.Bar = Bar; // I don't want to do this, but how can I avoid it?
Is there a better way? What am I missing?
Thanks in advance!
EDIT (6/7/11)
Adding a more specific example to my problem. Basically, there are abstract implementations for a Game and a Camera (very basic here...). The abstract Game uses the abstract Camera for basic work. The derived Game uses its derived Camera for its specialty work. In the end, I'd need both the derived and the abstract Cameras to work in their own scope.
I've given two different Camera implementations and two Game implementations to (hopefully) demonstrate the flexibility I'm looking for. Please note that Game1 uses a "hack" to force the base Camera to have a value- Game2 does not do this. Game1 has the behavior I want, but not the implementation I want.
class GameAndCameraExample
{
static void Main(string[] args)
{
new Game1().Play();
Console.WriteLine();
new Game2().Play();
Console.ReadLine();
}
// abstract camera
abstract class CameraBase
{
public void SpecialCameraBaseMethod()
{
Console.WriteLine("SpecialCameraBaseMethod");
}
}
// camera implementation
class ChaseCamera : CameraBase
{
public void SpecialChaseCameraMethod()
{
Console.WriteLine("SpecialChaseCameraMethod");
}
}
// a different camera implementation
class FlightCamera : CameraBase
{
public void SpecialFlightCameraMethod()
{
Console.WriteLine("SpecialFlightCameraMethod");
}
}
// abstract game
abstract class GameBase
{
public virtual CameraBase Camera { get; set; }
public GameBase() { }
public virtual void Play()
{
Console.WriteLine("GameBase.Camera is null? {0}", Camera == null);
if(Camera != null) // it will be null for Game2 :-(
Camera.SpecialCameraBaseMethod();
}
}
// awesome game using chase cameras
class Game1 : GameBase
{
public new ChaseCamera Camera { get; set; }
public Game1() : base()
{
Camera = new ChaseCamera();
base.Camera = Camera; // HACK: How can I avoid this?
}
public override void Play()
{
Console.WriteLine("Game.Camera is null? {0}", Camera == null);
Camera.SpecialChaseCameraMethod();
base.Play();
}
}
// even more awesome game using flight cameras
class Game2 : GameBase
{
public new FlightCamera Camera { get; set; }
public Game2()
: base()
{
Camera = new FlightCamera();
}
public override void Play()
{
Console.WriteLine("Game.Camera is null? {0}", Camera == null);
Camera.SpecialFlightCameraMethod();
base.Play();
}
}
}
OUTPUT:
Game.Camera is null? False SpecialChaseCameraMethod GameBase.Camera is null? False SpecialCameraBaseMethod Game.Camera is null? False SpecialFlightCameraMethod GameBase.Camera is null? True
Is inheritance even the best approach for this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您需要使用
override
而不是new
。您仍然可以返回一个
Bar
对象,尽管它仍然会作为BarBase
返回。但是,override
是确保在Foo< 时使用
Foo
的属性而不是FooBase
的属性的唯一方法。 /code> 对象被转换为FooBase
。在这种情况下,泛型可以提供帮助,主要是在
FooBase
类上:下面是对
Main()
的修改:泛型参数
T
的约束为BarBase
意味着FooBase
的任何子类都可以选择加入BarBase
的任何子类,或者只处理BarBase
:You need to use
override
instead ofnew
.You can still return a
Bar
object, thought it will still return asBarBase
. Butoverride
is the only way to make sure thatFoo
's property is used instead ofFooBase
's property when theFoo
object is cast asFooBase
.Generics could help in this situation, mainly on the
FooBase
class:And here's the modifications to
Main()
:The constraint of generic parameter
T
toBarBase
means any subclass ofFooBase
can opt-in to any subclass ofBarBase
, or just deal withBarBase
:我将回答我自己的问题。其实有两个答案。可能还有很多其他答案,但没有一个在这里找到答案。
解决方案#1:并行层次结构
这个想法是由 @Joel B Fant 在之前的评论中提出的。我研究了 ADO.NET 的实现方式(通过 Reflector)并提出了一个实现。我对这种模式并不感到兴奋,因为它意味着同一个对象系列有多个属性 - 但它是一个合理的解决方案。
(假设我的问题中的 CameraBase、FlightCamera 和 ChaseCamera 仍然被定义以节省空间)
代码
解决方案#2:继承、注入和扭曲
这个“模式”可能有一个真实的名字,但我不知道。它与并行层次结构(以及我的原始示例)非常相似,除了我通过构造函数注入相机并使用基本属性(带有转换)进行访问。我想我可以避免注入并直接分配给基本属性(但为什么要避免注入?它非常有用!)。 扭曲只是属性所需的转换。它不干净,但也不难看。这是我目前的首选解决方案。
代码
这两种解决方案都通过可接受的实现为我提供了所需的结果。
I'm going to present an answer to my own question. Actually, two answers. There are likely many other answers but none are finding their way here.
Solution #1: Parallel Hierarchies
This idea was brought up by @Joel B Fant in an earlier comment. I looked over how ADO.NET is implemented (via Reflector) to come up with an implementation. I'm not thrilled about this pattern because it means multiple properties for the same family of objects- but it is a reasonable solution.
(Let's assume that the CameraBase, FlightCamera, and ChaseCamera from my question are still defined to save space)
CODE
Solution #2: Inheritance, Injection, and a Twist
This "pattern" might have a real name, but I don't know it. It's very similar to Parallel Hierarchies (as well as my original example) except I'm injecting the camera through the constructor and using the base properties (with casting) for access. I suppose I could have avoided the injection and do a straight assignment to the base property as well (but why avoid injection? It's so useful!). The twist is simply the required casting for the properties. It's not clean, but it's not ugly either. This is my current preferred solution.
CODE
Both of these solutions give me the desired results with an acceptable implementation.
您可以尝试以下操作:将属性类型更改为 BarBase 并使用覆盖。然后使用多态性将派生类 Bar 对象分配给 BarBase 属性。属性栏是虚拟的,因此将返回正确的对象。
You may try this: change Property type to BarBase and use override. Then use polimorphism to assign a derived class Bar object to the BarBase Property. Property Bar is virtual so the right object will be returned.
这是解决方案的提示:
希望您发现这很有用。
-Zsolt
Heres a tip for solution:
Hope you find this useful.
-Zsolt