First of all, I would consider making an ability a component, so that it can be attached to any GameObject:
abstract class Ability : Component {
public abstract byte Id { get; }
public abstract Execute();
}
By making the byte id a property, you can easily override the property in each class and give it a unique value, without having to worry about keeping a list:
class MyConcreteAbility : Ability {
public override byte Id {
get { return 8; } // Byte value of your choosing
}
public override void Execute() {
// Your code here
}
}
(Just make sure not to use the same value twice.)
Additionally, I would add an overloaded version of the method Execute to the abstract Ability class, to serve as a message handler:
public void Execute(byte id) {
if(Id == id) {
executeExecute();
}
}
The ability's Execute method can then easily be invoked on all objects it is attached to by calling:
BroadcastMessage("Execute", 8)
Or on a specific object and all its children by calling:
gameObject.SendMessage("Execute", 8)
Of course, you can also simply call it directly.