-4

I have situation like this. Is it correct? If not how to do this correct?

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[] { });
        }
    }
}

result1 will be true result2 will be false

Is figure.GetType().GetMethod(nameof(Figure.SomeMethod)).Invoke(this, new object[] { }); correct?

Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
  • If you want `Pawn.SomeMethod()` called whenever you have a reference declared as `Figure` and try to call `Figure.SomeMethod()`, you should use `virtual` and `override` rather than method hiding. See [Overriding vs method hiding](https://stackoverflow.com/q/3838553). If you **sometimes** want `Figure.SomeMethod()` called, and sometimes `Pawn.SomeMethod()`, you should rethink your design. When do you need one called, and when the other? If you can characterize when you need each result, you should create different public methods on `Figure` to meet each requirement. – dbc Jan 01 '23 at 17:45
  • 2
    *"overridden by "new" keyword"*. There is no such thing. You override using the `override` keyword. If you use the `new` keyword then you're not overriding. In order to override, a method must be declared `virtual` in the first place. – jmcilhinney Jan 01 '23 at 17:47
  • In every Figures like King, Bishop etc. i use default "SomeMethod" but for Pawn is specific, so i need to wride "new" "SomeMethod" – Kacper Oracz Jan 01 '23 at 18:26
  • read https://www.dotnetperls.com/base – John Alexiou Jan 01 '23 at 18:51
  • @KacperOracz - this is exactly what I have implemented with my first option. Remove the `abstract` keyword from the class, and add the `virtual` keywords to the methods that derived classes have an opportunity (but not a requirement) to override. – John Alexiou Jan 01 '23 at 18:52

2 Answers2

0

I think your better off type-checking and casting than using reflection:

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

Newer C# versions allow you to use pattern matching:

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

But if you want to have the method always called from the subclass, why not mark the method as virtual (or abstract) in the base class and then override it in your subclasses?

Or perhaps you are looking for double-dispatch and want to implement something like the Visitor pattern.

knittl
  • 246,190
  • 53
  • 318
  • 364
  • Just a guess here, but I bet there are additional `Figure` subtypes including `King`, `Queen`, `Rook`, `Bishop` and `Knight`. – dbc Jan 01 '23 at 17:52
  • 1
    I think the OP would be better served with education in what overriding means rather than (or in addition to) how to call methods on subclasses. – Heretic Monkey Jan 01 '23 at 17:55
0

Have an implementation in your base class and declare methods virtual if intended to be overridden. In this case you do not need the abstract keyword as everything is defined for the base class.

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

Here the base functionality is exposed by the decedent classes with an additional method called BaseMethod(). Then you can use pattern matching to get to the Pawn specific methods.


I feel that you need to do some reading on how inheritance works.

Here is some test code with a base class containing 3 methods. One normal method CommonMethod(), one virtual method SpecialMethod() and one normal method, with the intent to hide in one derived class called FigureMethod().

The base class Figure has two derived classes Pawn and Queen that either override or re-define methods with the new keyword.

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

I call all three methods from 5 instances. Three instances of a base class Figure variables, and Two instances

The results are as follows:

    Variable   Common  Special   Figure
      figure      100        1       -1
  figurePawn      100        2       -1
 figureQueen      100        1       -1
        pawn      100        2       -1
       queen      100        1       10
  • All ways of calling CommonMethod() result in the same result.
  • The SpecialMethod() calls either use the base implementation or the specific one for Pawn types.
  • The FigureMethod() can only be called when the variable is scoped to a Queen type and it re-defines what this method does for this specific type.

As a general rule, do not use the new keyword unless absolutely necessary. This is because the re-defined method might have a completely different functionality than the general use one and can results in bugs and/or maintenance issues.

John Alexiou
  • 28,472
  • 11
  • 77
  • 133
  • I can't use virtual method cause if method is virtual i need to write the same code in every other Figure types. In every Figures like King, Bishop etc. i use default "SomeMethod" but for Pawn is specific, so i need to wride "new" "SomeMethod" – Kacper Oracz Jan 01 '23 at 18:31
  • That's why we composite rather than inherit. – Fildor Jan 01 '23 at 18:38
  • @KacperOracz `virtual` methods do not need to be overridden in every subclass. If you don't override it, the default implementation of the base will be used. Sounds exactly like what you want to do – knittl Jan 01 '23 at 18:48
  • @KacperOracz you need to edit your question and provide the necessary details and requirements. The "how to do this correct?" statement isn't helpful without an understanding what you want to do. – John Alexiou Jan 01 '23 at 18:48
  • @knittl Ok. I will try and tell you result :) – Kacper Oracz Jan 01 '23 at 18:50
  • @KacperOracz - see my updated answer that might help you understand how this works. – John Alexiou Jan 01 '23 at 19:17