Java -> C# Creating Anonymous Instance of Abstract

2020-04-18 08:37发布

问题:

for training purposes I am following along a Tutorial written for Java, which I successfully 'translated' into C# so far, however, I am facing now a problem for which I don't really have a clue how to solve it. The closest(?) possible answer to my problem I could find was this question. Though I have problems understanding delegates and lamba expressions for now. Anyways, here the relevant Code in Java:

public abstract class LevelUpOption {
  private String name;
  public String name() { return name; }

  public LevelUpOption(String name){
    this.name = name;
  }

  public abstract void invoke(Creature creature);
}

And another class:

public class LevelUpController {

    private static LevelUpOption[] options = new LevelUpOption[]{
        new LevelUpOption("Increased hit points"){
            public void invoke(Creature creature) { creature.gainMaxHp(); }
        },
        new LevelUpOption("Increased attack value"){
            public void invoke(Creature creature) { creature.gainAttackValue(); }
        },
        new LevelUpOption("Increased defense value"){
            public void invoke(Creature creature) { creature.gainDefenseValue(); }
        },
        new LevelUpOption("Increased vision"){
            public void invoke(Creature creature) { creature.gainVision(); }
        }
    };

    public void autoLevelUp(Creature creature){
        options[(int)(Math.random() * options.length)].invoke(creature);
    }

    public List<String> getLevelUpOptions(){
        List<String> names = new ArrayList<String>();
        for (LevelUpOption option : options){
            names.add(option.name());
        }
        return names;
    }

    public LevelUpOption getLevelUpOption(String name){
        for (LevelUpOption option : options){
            if (option.name().equals(name))
                return option;
        }
        return null;
    }
}

The problem I have is with this part:

private static LevelUpOption[] options = new LevelUpOption[]{
        new LevelUpOption("Increased hit points"){
            public void invoke(Creature creature) { creature.gainMaxHp(); }
        },
        new LevelUpOption("Increased attack value"){
            public void invoke(Creature creature) { creature.gainAttackValue(); }
        },
        new LevelUpOption("Increased defense value"){
            public void invoke(Creature creature) { creature.gainDefenseValue(); }
        },
        new LevelUpOption("Increased vision"){
            public void invoke(Creature creature) { creature.gainVision(); }
        }
    };

While easy to understand in terms what it is doing I have no clue how to write that relatively similiar in C#. I could work around it in very simplistic ways like with if or switch cases but I would like to keep it smooth to the original.

回答1:

There are no anonymous classes in C#, but you have two ways of achieving the same result:

  • Make private, nested, named classes, and reference them in the array initializer, or
  • Make a constructor take a delegate for each abstract method that you plan to override.

The first approach is self-explanatory, but the code would be quite a bit longer. The named classes should be OK, because they are private to the implementation of your publicly visible class.

The second approach could look as follows:

public class LevelUpOption {
  private String name;
  public String name() { return name; }

  public LevelUpOption(String name, Action<Creature> invoke){
    this.name = name;
    this.invoke = invoke;
  }

  public readonly Action<Creature> invoke;
}

Now you can initialize your array like this:

private static LevelUpOption[] options = new [] {
    new LevelUpOption("Increased hit points", c => c.gainMaxHp() ),
    new LevelUpOption("Increased attack value", c => c.gainAttackValue()),
    ...
};

Since invoke is a delegate, the syntax of calling it is the same:

options[i].invoke(myCreature);