“新"修饰符使基本实现具有NULL属性值 [英] "new" modifier causes base implementations to have NULL property values

查看:69
本文介绍了“新"修饰符使基本实现具有NULL属性值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Polymorphism使派生类使用派生属性而不是基本属性进行操作.我不确定如何用更清晰的词来表达,所以这是输出示例:

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?
    }
}

输出:


Foo is null? False
Foo.Bar is null? False
FooBase is null? False
FooBase.Bar is null? True

问题是"FooBase.Bar"为NULL.我知道 new 修饰符隐藏了基本实现,这就是为什么我知道我可以通过添加(注释掉)这一行来使其工作的原因:

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?

提前谢谢!

编辑(11/6/7)

为我的问题添加一个更具体的示例.基本上,有一个Game和Camera的抽象实现(在这里非常基本...).抽象游戏将抽象相机用于基本工作.派生游戏将派生相机用于其特殊工作.最后,我需要派生相机和抽象相机都可以在它们自己的范围内工作.

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.

我给出了两个不同的Camera实现和两个Game实现,以(希望)展示我正在寻找的灵活性.请注意,Game1使用"hack"来强制基础Camera具有一个值-Game2不会这样做. Game1具有我想要的行为,但没有我想要的实现.

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

输出:


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 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.

解决方案1:并行层次结构

这个想法是@Joel B Fant在较早的评论中提出的.我研究了如何(通过Reflector)实现ADO.NET来实现.我对这种模式并不感到兴奋,因为它意味着对象的同一家族具有多个属性,但这是一个合理的解决方案.

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.

(假设我的问题中的CameraBase,FlightCamera和ChaseCamera仍被定义为节省空间)

代码

// abstract game
abstract class GameBase
{
    public virtual CameraBase CameraBase { get; set; }
    public GameBase() { }
    public virtual void Play()
    {
        Console.WriteLine("GameBase.CameraBase is null? {0}", CameraBase == null);
        if (CameraBase != null)
            CameraBase.SpecialCameraBaseMethod();
    }
}

// awesome game using chase cameras
class Game1 : GameBase
{
    public override CameraBase CameraBase 
    { 
        get { return Camera; } 
        set { Camera = (ChaseCamera)value; } 
    }
    public ChaseCamera Camera { get; set; }
    public Game1()
    {
        Camera = new ChaseCamera();
    }
    public override void Play()
    {
        Console.WriteLine("Game.Camera is null? {0}", Camera == null);
        Camera.SpecialChaseCameraMethod();
        base.Play();
    }
}

解决方案2:继承,注入和扭曲

此样式"可能有真实姓名,但我不知道.它与Parallel Hierarchies(以及我的原始示例)非常相似,只不过我是通过构造函数注入相机并使用基本属性(带有强制转换)进行访问.我想我可以避免注入,也可以直接对基属性进行赋值(但是为什么要避免注入?它是如此有用!). 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.

代码

// must inject the camera for this solution
static void Main(string[] args)
{
    new Game1(new ChaseCamera()).Play();
    Console.ReadLine();
}

// abstract game
abstract class GameBase
{
    public virtual CameraBase Camera { get; set; }
    public GameBase(CameraBase camera) // injection
    {
        Camera = camera;
    }
    public virtual void Play()
    {
        Console.WriteLine("GameBase.Camera is null? {0}", Camera == null);
        if (Camera != null)
            Camera.SpecialCameraBaseMethod();
    }
}

// awesome game using chase cameras
class Game1 : GameBase
{
    public new ChaseCamera Camera 
    { 
        get { return (ChaseCamera)base.Camera; } 
        set { base.Camera = value; } 
    }
    public Game1(ChaseCamera camera) : base(camera) { } // injection
    public override void Play()
    {
        Console.WriteLine("Game.Camera is null? {0}", Camera == null);
        Camera.SpecialChaseCameraMethod();
        base.Play();
    }
}

这两种解决方案都可以通过可接受的实现为我带来预期的结果.

Both of these solutions give me the desired results with an acceptable implementation.

这篇关于“新"修饰符使基本实现具有NULL属性值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆