Ben
Ben

Reputation: 16669

Override abstract field in child classes

In C#, is it possible to have an abstract parent class that declares a field of a type that itself corresponds to an abstract class and must be overridden in the child classes?

Here's the idea:

public abstract class AbstractInfo {
    // ...
    public GameplayResult gameplayResult;
}

public class LevelInfo : AbstractInfo {
    // ...
    public LevelGameplayResult gameplayResult;
}

public class BossInfo : AbstractInfo {
    // ...
    public BossGameplayResult gameplayResult;
}

With:

public abstract class GameplayResult {
    // ...
}

public class LevelGameplayResult : GameplayResult {
    // ...
}

public class BossGameplayResult : GameplayResult {
    // ...
}

The goal is to be able to have another class:

public class Manager {
    // ...    

    public AbstractInfo info;

    public void UpdateInfo(GameplayResult gameplayResult) {
        info.gameplayResult = gameplayResult;
        // Where info could be a level info or boss info
        // and gameplay result could be a level or boss gameplay result    
    }
}

Upvotes: 0

Views: 399

Answers (1)

Xerillio
Xerillio

Reputation: 5261

There are a couple of issues in the example you've given.

  1. Although it isn't invalid, currently, your derived classes are hiding the base class's member gameplayResult and thus redeclaring them. If you're looking for overriding a member, you need to use the override keyword in the derived class and make the member abstract or virtual in the base class. Furthermore, a member field cannot be abstract, but you can use a property instead:
public abstract class AbstractInfo
{
    public abstract GameplayResult GameplayResult { get; set; }
}

public class LevelInfo : AbstractInfo
{
    // Still something wrong here (see #2)
    public override LevelGameplayResult GameplayResult { get; set; }
    // For later demonstration...
    public bool IAmLevelInfo { get; } = true;
}
  1. You cannot change the type of an overridden member.

Consider the example:

public void DoSomethingWithInfo(AbstractInfo info)
{
    info.GameplayResult = new BossGameplayResult();
}

var lvlInf = new LevelInfo();

// Some time later...

DoSomethingWithInfo(lvlInfo);

if (!lvlInfo.IAmLevelInfo)
{
    Console.WriteLine("How did this happen o.O")?
}

In the above example it should be completely legal to call DoSomethingWithInfo(lvlInfo) because LevelInfo is also an AbstractInfo. Inside the method we're trying to assign a BossGameplayResult to an AbstractInfo's GameplayResult which is completely legal. However, we passed in a LevelInfo which does not allow you to assign a BossGameplayResult to GameplayResult. So we've hit a paradox. Of course, the above won't even compile, because the compiler is clever enough to realize this.

To solve this issue, you can use generics:

public abstract class AbstractInfo<T> where T : GameplayResult
{
    public T GameplayResult { get; set; }
}

public class LevelInfo : AbstractInfo<LevelGameplayResult>
{
    // No need for overriding, as 'GameplayResult' will
    // have type 'LevelGameplayResult'
}

Upvotes: 1

Related Questions