Eagle-Eye
Eagle-Eye

Reputation: 1498

How do I override, not hide, a member variable (field) in a C# subclass?

I want this to tell me the Name of both ItemA and ItemB. It should tell me "Subitem\nSubitem", but instead it tells me "Item\nSubitem". This is because the "Name" variable defined in the Subitem class is technically a different variable than the "Name" variable defined in the base Item class. I want to change the original variable to a new value. I don't understand why this isn't the easiest thing ever, considering virtual and override work perfectly with methods. I've been completely unable to find out how to actually override a variable.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Example
{
    class Program
    {
        static void Main(string[] args)
        {
            System.Console.WriteLine(ItemA.Name);
            System.Console.WriteLine(ItemB.Name);
            System.Console.ReadKey();
        }
        static Item ItemA = new Subitem();
        static Subitem ItemB = new Subitem();
    }
    public class Item
    {
        public string Name = "Item";
    }
    public class Subitem : Item
    {
        new public string Name = "Subitem";
    }
}

Upvotes: 39

Views: 66119

Answers (6)

GhostoTheGreat
GhostoTheGreat

Reputation: 1

I had a similar problem to this, where member variables were themselves class objects that inherited from each other. After a lot of researching and tinkering, I came up with a good solution for me. Here I am sharing it in the hope that it will help someone else. (And yes, I realize that this is an old post, but as it was at the top for my google searches . . .)

My goal was for Unity to show in the editor the specific stats class for each item category. In other words, I wanted a Weapon Object when selected to show WeaponStats, and an Armor Object when selected to show ArmorStats, all while Weapon and Armor had shared variables and WeaponStats and ArmorStats also had shared variables.

Specifically, I was trying to use the new keyword so that a base variable (of a class type) could be overridden by the derived class's variable (of a type derived from the base variable's class). As in:

public class ItemStats {
    // variables like size, weight, etc
}

public class WeaponStats : ItemStats {
    // Additional variables like damage, rate of fire, etc
}

public class ArmorStats : ItemStats {
    // Additional variables like degree of damage reduction, etc

public class Item {
    public ItemStats stats;
    protected float degredation;
    // etc.
}

public class Weapon : Item {
    public new WeaponStats stats; // *The problem*
    protected Ammo ammo;
    // etc
}

public class Armor : Item {
    public new ArmorStats stats; // *Same problem*
    // etc
}

However, this didn't actually hide the base ItemStats variable and instead hid the new WeaponStats variable. As well as creating a lot of headache about what variable stats was referring to in the Weapon class. tldr it was a bad idea.

The better solution I finally came up with, after learning a lot more about inheritance, was this:

// Make the base class abstract, so each item has its own subclass.
// This avoids having two variables for stats, the problem I was trying to avoid.
public abstract class Item {
    public abstract ItemStats Stats();
    // notice that there is no ItemStats variable here anymore
    protected float degredation;
    // etc.
}

public class Weapon : Item {
    public WeaponStats stats;
    protected Ammo ammo;

    // This function lets other items interface with its stats.
    public override ItemStats Stats() {
        return stats;
    }
    // etc
}

// The same idea for Armor as for Weapon

This enabled Unity's Editor to only display the matching stats class (WeaponStats with Weapons and ArmorStats with Armor, for example); gave each Stats class inherited variables common to all ItemsStats; and also allowed all Items to know that other Items had stats.

Hope this is helpful to someone else :)

Upvotes: 0

x3ro
x3ro

Reputation: 328

This question is relatively old and the author was probably using C# 5.0 or lower. But I had the same question and came across a very neat solution that works with C# 6.0 and higher that I want to share with you:

C# 6.0 gives the ability to initialize auto-properties. So one can use just that:

public class Item
{
    public virtual string Name { get; set; } = "Item";
}

public class Subitem : Item
{
    public override string Name { get; set; } = "Subitem";
}

Upvotes: 7

Jon Hanna
Jon Hanna

Reputation: 113372

What would "overriding a variable" mean?

A variable is a named location in conceptual memory ("conceptual", because it could be a register, though not very likely with fields).

Overriding a method substitutes one set of operations for another.

Since a named location in memory isn't a set of operations, how can you substitute it? What are things that expect to use that named location in memory supposed to do?

If you want to change what is stored in the memory, then just do so when the derived class is constructed:

public class Item
{
  public string Name = "Item";
}
public class Subitem : Item
{
  public SubItem()
  {
    Name = "Subitem";
  }
}

If you want to override as set of operations, then define a set of operations (a method or property) to override.

Upvotes: 7

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726987

You cannot override variables in C#, but you can override properties:

public class Item
{
    public virtual string Name {get; protected set;}
}
public class Subitem : Item
{
    public override string Name {get; protected set;}
}

Another approach would be to change the value in the subclass, like this:

public class Item
{
    public string Name = "Item";
}
public class Subitem : Item
{
    public Subitem()
    {
        Name = "Subitem";
    }
}

Upvotes: 56

Jesse Emond
Jesse Emond

Reputation: 7490

A possible solution would be to use a property and override its getter, like so:

public class Item
{
    public virtual string Name { get { return "Item"; } }
}
public class Subitem : Item
{
    public override string Name { get { return "Subitem"; } }
}

Upvotes: 1

Adam Robinson
Adam Robinson

Reputation: 185693

There is no concept of polymorphism (which is what makes override do its thing) with fields (what you call a variables). What you need to use here instead is a property.

public class Item
{
    public virtual string Name
    {
        get { return "Item"; }
    }
}

public class SubItem : Item
{
    public override string Name
    {
        get { return "Subitem"; }
    }
}

Upvotes: 10

Related Questions