locked
Overriding Class Methods when instantiating class? RRS feed

  • Question

  • HI,

     I was looking through the source code for a Java program and saw some functionality that I'd like to replicate in a C# program, but I'm unsure of how to do it - I was thinking anonymous methods, but that doesn't seem to be quite what I'm looking for. If you look at the code below, it looks like the writer is able to override the "use" method when declaring a new object. If I'm reading this wrong let me know, but my main question is, is this replicatable in C#? It'd be alot easier then having to declare alot of different class/overloads for things that only have a minor differences in their methods. I included all the source code for the base classes below.

    //Two examples of the functionality I'm interested in 
    
    
    
    m_moves.add(new MoveListEntry("Fake Out",
    
                new PokemonMove(PokemonType.T_NORMAL, 40, 1.0, 10) {
    
                    public int use(BattleMechanics mech, Pokemon user, Pokemon target) {
    
                        if (!user.isFirstTurn()) {
    
                            user.getField().showMessage("But it failed!");
    
                            return 0;
    
                        }
    
                        if ((getEffectiveness(user, target) != 0.0) && !target.hasSubstitute()) {
    
                            target.addStatus(user, new FlinchEffect());
    
                        }
    
                        return super.use(mech, user, target);
    
                    }
    
                    public int getPriority() {
    
                        return 1;
    
                    }
    
                }
    
            )); 
    
    
    
    
    
    m_moves.add(new MoveListEntry("Outrage",
    
                    new RampageMove(PokemonType.T_DRAGON, 120, 1.0, 15) {
    
                        public int use(BattleMechanics mech, Pokemon user, Pokemon target) {
    
                            setPower((int)(((double)getPower()) / 120.0 * ((mech instanceof JewelMechanics) ? 120.0 : 90.0)));
    
                            return super.use(mech, user, target);
    
                        }
    
                }));
    
    
    
    //RampageMove Base Class
    
    
    
    private static class RampageMove extends PokemonMove {
    
            public RampageMove(PokemonType type, int power, double accuracy, int pp) {
    
                super(type, power, accuracy, pp);
    
            }
    
            public int use(BattleMechanics mech, Pokemon user, Pokemon target) {
    
                user.addStatus(user, new StatusEffect() {
    
                    private int m_turns = 0;
    
                    public boolean apply(Pokemon p) {
    
                        m_turns = 2 + p.getField().getMechanics().getRandom().nextInt(2);
    
                        return true;
    
                    }
    
                    public String getName() {
    
                        return getMoveListEntry().getName();
    
                    } 
    
                    public String getDescription() {
    
                        return " went on a rampage!";
    
                    }
    
                    public int getTier() {
    
                        return 1;
    
                    }
    
                    public boolean canSwitch(Pokemon p) {
    
                        return false;
    
                    }
    
                    public boolean vetoesMove(Pokemon p, MoveListEntry move) {
    
                        return !getMoveListEntry().equals(move);
    
                    }
    
                    public boolean tick(Pokemon p) {
    
                        if (--m_turns == 0) {
    
                            p.getField().showMessage(p.getName() + "'s rampage ended.");
    
                            p.removeStatus(this);
    
                            p.addStatus(p, new ConfuseEffect());
    
                        }
    
                        return true;
    
                    }
    
                });
    
                return super.use(mech, user, target);
    
            }
    
        }
    
    //PokemonMove Class
    
    public class PokemonMove implements Cloneable {
    
        
    
        protected PokemonType m_type;
    
        protected int m_power;
    
        protected double m_accuracy;
    
        protected int m_pp;
    
        protected MoveListEntry m_entry;
    
        
    
        /**
    
         * Initialise a typical attacking move.
    
         */
    
        public PokemonMove(PokemonType type, int power, double accuracy, int pp) {
    
            m_type = type;
    
            m_power = power;
    
            m_accuracy = accuracy;
    
            m_pp = pp;
    
        }
    
        
    
        /**
    
         * Set this move's entry in the move list.
    
         */
    
        /*package*/ void setMoveListEntry(MoveListEntry e) {
    
            m_entry = e;
    
        }
    
        
    
        /**
    
         * Return this move's entry in the move list.
    
         */
    
        public MoveListEntry getMoveListEntry() {
    
            return m_entry;
    
        }
    
        
    
        /**
    
         * Return whether this move should use special attack and defence.
    
         */
    
        public boolean isSpecial(BattleMechanics mech) {
    
            return mech.isMoveSpecial(this);
    
        }
    
        
    
        /**
    
         * Clone this move.
    
         */
    
        public Object clone() {
    
            try {
    
                return super.clone();
    
            } catch (CloneNotSupportedException e) {
    
                /* unreachable */
    
                return null;
    
            }
    
        }
    
        
    
        /**
    
         * Attempt to hit an enemy.
    
         */
    
        public boolean attemptHit(BattleMechanics mech, Pokemon user, Pokemon target) {
    
            return mech.attemptHit(this, user, target);
    
        }
    
        
    
        /**
    
         * Cause a pokemon to use this move on another pokemon.
    
         */
    
        public int use(BattleMechanics mech, Pokemon user, Pokemon target) {
    
            int damage = mech.calculateDamage(this, user, target);
    
            target.changeHealth(-damage);
    
            return damage;
    
        }
    
        
    
        /**
    
         * Get PP.
    
         */
    
        public int getPp() {
    
            return m_pp;
    
        }
    
        
    
        /**
    
         * Return whether this move deals damage.
    
         */
    
        public boolean isDamaging() {
    
            return isAttack();
    
        }
    
        
    
        /**
    
         * Get accuracy.
    
         */
    
        public double getAccuracy() {
    
            return m_accuracy;
    
        }
    
        
    
        /**
    
         * Set the accuracy of this move.
    
         */
    
        public void setAccuracy(double accuracy) {
    
            if (accuracy > 1.0) {
    
                m_accuracy = 1.0;
    
            } else if (accuracy < 0.0) {
    
                m_accuracy = 0.0;
    
            } else {
    
                m_accuracy = accuracy;
    
            }
    
        }
    
        
    
        /**
    
         * Get the type of this move.
    
         */
    
        public PokemonType getType() {
    
            return m_type;
    
        }
    
        
    
        /**
    
         * Some moves can be used even if a status effect (e.g. sleep) would
    
         * normally prevent it. If this move can be used a such, the class
    
         * of the status effect is returned by this method. Otherwise, the method
    
         * returns null.
    
         */
    
        public Class getStatusException() {
    
            return null;
    
        }
    
        
    
        /**
    
         * Get the effectiveness of this move against a denfending pokemon.
    
         */
    
        public double getEffectiveness(Pokemon user, Pokemon defender) {
    
            return getEffectiveness(m_type, user, defender);
    
        }
    
        
    
        /**
    
         * Get the effectiveness of one type of move against an arbitrary pokemon.
    
         */
    
        public static double getEffectiveness(PokemonType type, Pokemon user, Pokemon defender) {
    
            PokemonType[] defTypes = defender.getTypes();
    
            double multiplier = 1.0;
    
            for (int i = 0; i < defTypes.length; ++i) {
    
                double expected = type.getMultiplier(defTypes[i]);
    
                double factor;
    
                PokemonType def = defTypes[i];
    
                if (user != null) {
    
                    factor = user.getEffectiveness(type, def, false);
    
                    if (factor == expected) {
    
                        factor = defender.getEffectiveness(type, def, true);
    
                    }
    
                } else {
    
                    BattleField field = defender.getField();
    
                    factor = field.getEffectiveness(type, def, false);
    
                    if (factor == expected) {
    
                        factor = field.getEffectiveness(type, def, true);
    
                    }
    
                }
    
                multiplier *= factor;
    
            }
    
            return multiplier;
    
        }
    
        
    
        /**
    
         * This method is called when a pokemon who has this move is switched into
    
         * the field.
    
         */
    
        public void switchIn(Pokemon p) {
    
            
    
        }
    
        
    
        /**
    
         * Return whether this move can strike critical.
    
         */
    
        public boolean canCriticalHit() {
    
            return true;
    
        }
    
        
    
        /**
    
         * Set the type of this move.
    
         */
    
        public void setType(PokemonType type) {
    
            m_type = type;
    
        }
    
        
    
        /**
    
         * Get the power of this move.
    
         */
    
        public int getPower() {
    
            return m_power;
    
        }
    
        
    
        /**
    
         * Set the power of this move.
    
         */
    
        public void setPower(int power) {
    
            m_power = power;
    
        }
    
        
    
        /**
    
         * Get the priority of this move. Priority determines when this move will
    
         * be used during the turn.
    
         */
    
        public int getPriority() {
    
            return 0;
    
        }
    
        
    
        /**
    
         * Determine whether this move has a high chance of striking a critical
    
         * hit.
    
         */
    
        public boolean hasHighCriticalHitRate() {
    
            return false;
    
        }
    
        
    
        /**
    
         * Returns whether this move is an attack. This method is shoddy and should 
    
         * be overridden by any exceptions.
    
         */
    
        public boolean isAttack() {
    
            return m_power != 0;
    
        }
    
        
    
        /**
    
         * This function is called at the beginning on a turn on which this move
    
         * is about to be used.
    
         * @param turn the moves about to be used on this turn
    
         * @param index the position of the source pokemon in the turn array
    
         * @param source the pokemon who is using the move
    
         */
    
        public void beginTurn(BattleTurn[] turn, int index, Pokemon source) {
    
            
    
        }
    
        
    
        /**
    
         * Return whether this move is buggy.
    
         */
    
        public boolean isBuggy() {
    
            return false;
    
        }
    
    }
    
    
    
    
    
    
    
    //MoveListEntry Class
    
    public class MoveListEntry implements Serializable, Cloneable {
    
        
    
        private static final long serialVersionUID = 873410794589044553L;
    
        
    
        private String m_name;
    
        transient private PokemonMove m_move;
    
        
    
        public Object clone() {
    
            try {
    
                MoveListEntry ret = (MoveListEntry)super.clone();
    
                if (ret.m_move != null) {
    
                    ret.m_move = (PokemonMove)ret.m_move.clone();
    
                    ret.m_move.setMoveListEntry(ret);
    
                }
    
                return ret;
    
            } catch (CloneNotSupportedException e) {
    
                /* unreachable */
    
                return null;
    
            }
    
        }
    
        
    
        public boolean equals(Object o) {
    
            if (!(o instanceof MoveListEntry)) {
    
                return false;
    
            }
    
            return m_name.equals(((MoveListEntry)o).m_name);
    
        }
    
        
    
        private void writeObject(ObjectOutputStream out) throws IOException {
    
            out.defaultWriteObject();
    
        }
    
        
    
        private void readObject(ObjectInputStream in)
    
                throws IOException, ClassNotFoundException {
    
            in.defaultReadObject();
    
            MoveListEntry entry = MoveList.getDefaultData().getMove(m_name);
    
            if (entry != null) {
    
                m_move = entry.getMove();
    
            } else {
    
                m_move = null;
    
            }
    
        }
    
        
    
        public MoveListEntry(String name, PokemonMove move) {
    
            m_name = name;
    
            m_move = move;
    
            if (m_move.getMoveListEntry() != null) {
    
                System.out.println(name + " is used by two MoveListEntries!");
    
            }
    
            m_move.setMoveListEntry(this);
    
            if (m_move.isBuggy()) {
    
                System.out.println(name + " is buggy.");
    
            }
    
        }
    
        
    
        public String getName() {
    
            return m_name;
    
        }
    
        
    
        public PokemonMove getMove() {
    
            return m_move;
    
        }
    
    }

     

    Friday, February 26, 2010 2:37 PM

Answers

All replies

  • I think you need to start with an easier example...

    there are several ways of stylising basically the same thing...see

    the Foo class does it by having a mutable field that you can assign to...
    I prefer Foo2, because Foo2 forces you to implement the 'override'.
    You can also look at the decorator pattern where you can do the same thing again in styalised manner.


    the example gives two implementations that allow the client code to override the 'method'.

        class Program
        {
            static void Main(string[] args)
            {
                Foo foo = new Foo() { barMethod = (x) => x.ToString() };
                var z = foo.barMethod(1);

                Foo2 foo2 = new Foo2((x) => x.ToString());
                var z2 = foo2.barMethod(1);

            }
        }

        class Foo
        {
            public Func<int, string> barMethod;
        }

        class Foo2
        {
            public readonly Func<int, string> barMethod;

            public Foo2(Func<int, string> barMethod)
            {
                this.barMethod = barMethod;
            }
        }

    Friday, February 26, 2010 4:25 PM
  • I believe you are speaking of Anonymous Inner Classes , which has no equivalent in C#.

    The closest you might get is using Anonymous Methods .  You can read more about them here: http://msdn.microsoft.com/en-us/library/0yw3tz5k%28VS.80%29.aspx
    • Proposed as answer by JediJohn82 Friday, February 26, 2010 6:47 PM
    • Marked as answer by Gary Oak Friday, February 26, 2010 8:35 PM
    Friday, February 26, 2010 4:25 PM
  • Since you come from Java, surely you have heard of SSCCE.  Why not use that so we don't have to read 200 lines of java of which 150 are irrelevant to your question.  This also shows us that you have put actual effort into condensing the issue.


    BrianMackey.NET
    Friday, February 26, 2010 4:41 PM
  • But now we know how to get the best effectiveness for our Pikachu! :-)
    www.insteptech.com ; msmvps.com/blogs/deborahk
    We are volunteers and ask only that if we are able to help you, that you mark our reply as your answer. THANKS!
    Friday, February 26, 2010 5:14 PM
  • Sorry. I'd edit it out but everytime I go to edit on here, it adds extra lines between everything in the code block which makes it worse.
    Friday, February 26, 2010 5:59 PM
  • Don't edit the code within the forum.  Its buggy.  Cut ALL the code out of the forum and paste it into an ide/text editor.  Then, paste the code back in using the insert code block feature.
    BrianMackey.NET
    Friday, February 26, 2010 6:48 PM