.net 如何正确使用被覆盖的方法(被“new”关键字覆盖)?[duplicate]

5q4ezhmt  于 2023-01-03  发布在  .NET
关注(0)|答案(2)|浏览(214)
    • 此问题在此处已有答案**:

Overriding methods in C#(2个答案)
昨天关门了。
我有这样的情况。它是正确的吗?如果不正确怎么做?

namespace Chess
{
    public abstract class Figure
    {
        public bool SomeMethod()
        {
            return true;
        }
    }

    public class Pawn : Figure
    {
        public new bool SomeMethod()
        {
            return false;
        }
    }

    public class Board
    {

        public void SomeBoardMethod()
        {
            Figure figure = new Pawn();
            var result1 = figure.SomeMethod();
            var result2 = figure.GetType().GetMethod(nameof(Figure.SomeMethod)).Invoke(this, new object[] { });
        }
    }
}

结果1为真结果2为假
figure.GetType().GetMethod(nameof(Figure.SomeMethod)).Invoke(this, new object[] { });是否正确?

b4lqfgs4

b4lqfgs41#

我认为类型检查和强制转换比使用反射更好:

Figure figure = new Pawn();
var result1 = figure.SomeMethod();
Pawn pawn = figure as Pawn;
if (pawn != null) {
  var result2 = pawn.SomeMethod();
}

较新的C#版本允许您使用模式匹配:

Figure figure = new Pawn();
var result1 = figure.SomeMethod();
if (figure is Pawn pawn) {
  var result2 = pawn.SomeMethod();
}

但是,如果您希望始终从子类调用该方法,为什么不在基类中将该方法标记为virtual(或abstract),然后在子类中标记为override呢?
或者,您可能正在寻找双分派,并希望实现类似Visitor pattern的东西。

hkmswyz6

hkmswyz62#

在基类中有一个实现,如果要重写,则声明方法virtual。在这种情况下,不需要abstract关键字,因为所有内容都是为基类定义的。

namespace Chess
{
    public class Figure
    {
        public virtual bool SomeMethod()
        {
            return true;
        }
    }

    public class Pawn : Figure
    {
        public override bool SomeMethod()
        {
            return false;
        }
        public bool BaseMethod()
        {
            return base.SomeMethod();
        }
    }

    public class Board
    {

        public void SomeBoardMethod()
        {
            Figure figure = new Pawn();
            var result1 = figure.SomeMethod();
            if (figure is Pawn pawn)
            {
                var result2 = pawn.BaseMethod();
            }
        }
    }
}

这里的基本功能由继承类通过一个名为BaseMethod()的附加方法公开,然后您可以使用模式匹配来获得Pawn特定的方法。
我觉得你需要读一些关于继承如何工作的书。
下面是一些测试代码,基类包含3个方法。一个普通方法CommonMethod(),一个虚方法SpecialMethod()和一个普通方法,意图隐藏在一个名为FigureMethod()的派生类中。
基类Figure有两个派生类PawnQueen,它们要么是override,要么是用new关键字重新定义方法。

namespace Chess
{
    public class Figure
    {
        public int CommonMethod()
        {
            return 100;
        }
        public virtual int SpecialMethod()
        {
            return 1;
        }
        public int FigureMethod()
        {
            return -1;
        }
    }

    public class Pawn : Figure
    {
        public override int SpecialMethod()
        {
            return 2;
        }
    }
    public class Queen : Figure
    {
        public new int FigureMethod()
        {
            return 10;
        }
    }

    static class Program
    {
        static void Main(string[] args)
        {
            Figure figure = new Figure();
            Figure figurePawn = new Pawn();
            Figure figureQueen = new Queen();
            Pawn pawn = new Pawn();
            Queen queen = new Queen();

            Console.WriteLine($"{"Variable",12} {"Common",8} {"Special",8} {"Figure",8}");

            Console.WriteLine($"{nameof(figure),12} {figure.CommonMethod(),8} {figure.SpecialMethod(),8} {figure.FigureMethod(),8}");
            Console.WriteLine($"{nameof(figurePawn),12} {figurePawn.CommonMethod(),8} {figurePawn.SpecialMethod(),8} {figurePawn.FigureMethod(),8}");
            Console.WriteLine($"{nameof(figureQueen),12} {figureQueen.CommonMethod(),8} {figureQueen.SpecialMethod(),8} {figureQueen.FigureMethod(),8}");
            Console.WriteLine($"{nameof(pawn),12} {pawn.CommonMethod(),8} {pawn.SpecialMethod(),8} {pawn.FigureMethod(),8}");
            Console.WriteLine($"{nameof(queen),12} {queen.CommonMethod(),8} {queen.SpecialMethod(),8} {queen.FigureMethod(),8}");
        }
    }
}

我从5个示例调用了所有三个方法。3个示例是基类Figure变量,2个示例是
结果如下:

Variable   Common  Special   Figure
      figure      100        1       -1
  figurePawn      100        2       -1
 figureQueen      100        1       -1
        pawn      100        2       -1
       queen      100        1       10
  • 调用CommonMethod()的所有方法都产生相同的结果。
  • SpecialMethod()调用使用基本实现或Pawn类型的特定实现。
  • 只有当变量的作用域为Queen类型并且它重新定义了此方法对此特定类型的作用时,才能调用FigureMethod()

一般来说,除非绝对必要,否则不要使用new关键字。这是因为重新定义的方法可能具有与常规方法完全不同的功能,并且可能导致错误和/或维护问题。

相关问题