“新”修饰符导致基本实现具有 NULL 属性值

发布于 2024-11-13 06:36:46 字数 4207 浏览 3 评论 0原文

我正在尝试使用多态性让派生类使用派生属性而不是基属性进行操作。我不知道如何用更清晰的语言表达它,所以这里有一个输出示例:

// 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

我很OK 2024-11-20 06:36:46

您需要使用override而不是new

您仍然可以返回一个 Bar 对象,尽管它仍然会作为 BarBase 返回。但是,override 是确保在 Foo< 时使用 Foo 的属性而不是 FooBase 的属性的唯一方法。 /code> 对象被转换为 FooBase

在这种情况下,泛型可以提供帮助,主要是在 FooBase 类上:

class FooBase<T> where T: BarBase {
    public virtual T Bar { get; set; }
    public FooBase() { }
}

class Foo : FooBase<Bar> {
    public override Bar Bar { get; set; }
    public Foo() : base() {
        Bar = new Bar();
    }
}

下面是对 Main() 的修改:

static void Main( string[] args ) {
    var foo = new Foo();
    var foobase = foo as FooBase<Bar>;

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

泛型参数 T 的约束为BarBase 意味着 FooBase 的任何子类都可以选择加入 BarBase 的任何子类,或者只处理 BarBase

class VagueFoo : FooBase<BarBase> { }

You need to use override instead of new.

You can still return a Bar object, thought it will still return as BarBase. But override is the only way to make sure that Foo's property is used instead of FooBase's property when the Foo object is cast as FooBase.

Generics could help in this situation, mainly on the FooBase class:

class FooBase<T> where T: BarBase {
    public virtual T Bar { get; set; }
    public FooBase() { }
}

class Foo : FooBase<Bar> {
    public override Bar Bar { get; set; }
    public Foo() : base() {
        Bar = new Bar();
    }
}

And here's the modifications to Main():

static void Main( string[] args ) {
    var foo = new Foo();
    var foobase = foo as FooBase<Bar>;

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

The constraint of generic parameter T to BarBase means any subclass of FooBase can opt-in to any subclass of BarBase, or just deal with BarBase:

class VagueFoo : FooBase<BarBase> { }
疏忽 2024-11-20 06:36:46

我将回答我自己的问题。其实有两个答案。可能还有很多其他答案,但没有一个在这里找到答案。

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

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

(假设我的问题中的 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:继承、注入和扭曲

这个“模式”可能有一个真实的名字,但我不知道。它与并行层次结构(以及我的原始示例)非常相似,除了我通过构造函数注入相机并使用基本属性(带有转换)进行访问。我想我可以避免注入并直接分配给基本属性(但为什么要避免注入?它非常有用!)。 扭曲只是属性所需的转换。它不干净,但也不难看。这是我目前的首选解决方案。

代码

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

这两种解决方案都通过可接受的实现为我提供了所需的结果。

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

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

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

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

夜灵血窟げ 2024-11-20 06:36:46
class Foo : FooBase
{
    public override BarBase 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?
    }
}

您可以尝试以下操作:将属性类型更改为 BarBase 并使用覆盖。然后使用多态性将派生类 Bar 对象分配给 BarBase 属性。属性栏是虚拟的,因此将返回正确的对象。

class Foo : FooBase
{
    public override BarBase 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?
    }
}

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.

牛↙奶布丁 2024-11-20 06:36:46

这是解决方案的提示:

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<T> where T : CameraBase, new()
    {
        public T Camera { get; set; }

        public GameBase()
        {
            Camera = new T();
        }

        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<ChaseCamera>
    {
        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<FlightCamera>
    {
        public override void Play()
        {
            Console.WriteLine("Game.Camera is null? {0}", Camera == null); 
            Camera.SpecialFlightCameraMethod(); 
            base.Play();
        }
    }
}

希望您发现这很有用。
-Zsolt

Heres a tip for solution:

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<T> where T : CameraBase, new()
    {
        public T Camera { get; set; }

        public GameBase()
        {
            Camera = new T();
        }

        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<ChaseCamera>
    {
        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<FlightCamera>
    {
        public override void Play()
        {
            Console.WriteLine("Game.Camera is null? {0}", Camera == null); 
            Camera.SpecialFlightCameraMethod(); 
            base.Play();
        }
    }
}

Hope you find this useful.
-Zsolt

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文