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

6

39

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";
    }
}
Thirtieth answered 13/1, 2012 at 1:8 Comment(1)
You need something that can be virtual -- a Property ("Getter") or a Method. Member variables are never virtual.Fernandafernande
L
53

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";
    }
}
Level answered 13/1, 2012 at 1:11 Comment(3)
@Thirtieth What would polymorphic variables do? Don't criticise the practice if you can't articulate the theory.Winterkill
+1 to Jon, @Eagle-Eye. Given that polymorphism is about substituting functionality in derived types, applying it to something like fields (which have no functionality) does not make sense.Lockwood
@Jon Rereading my comment now it was a bit stupid to say. What I really meant was that I wish I could set the default value of a variable within a child class without having it in the constructor (since I came from a scripting language where that was how it was done). I did a poor job of expressing that previously. However, what does "don't criticise the practice if you can't articulate the theory" even mean? As far as "the other methods seem stupid and hacky," I was referring to my making a get method simply to have a separate default value. (I do regret the use of the word stupid, however.)Thirtieth
L
10

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"; }
    }
}
Lockwood answered 13/1, 2012 at 1:10 Comment(3)
Though he probably wouldn't hardcode the values like that, it may vary.Irretentive
Absolutely correct. A "virtual variable" makes no sense. Which is a large part of why Java-style "getter()" and "setter()" methods are so useful. And C#'s notion of "properties" (an advance from Delphi's already-very-good "properties") eliminates much of the need for getter/setter methods. "Properties" is definitely the answer to this question. See also this thread: #1112958Epirogeny
@JeffMercado: While true, I was trying to stick as closely to the original form of the OP's question so as to demonstrate the distinction I'm talking about (properties vs. fields).Lockwood
W
7

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.

Winterkill answered 13/1, 2012 at 1:17 Comment(0)
N
7

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";
}
Neurotic answered 12/8, 2017 at 21:30 Comment(2)
The most intuitive solution for me!Kinsley
This is what I figured it should be, now just need to determine why my project isn't using C#6 in 2021 lol...Labellum
A
1

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"; } }
}
Argilliferous answered 13/1, 2012 at 1:12 Comment(1)
This would prevent changing the value later on.Neurotic
S
0

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 :)

Script answered 7/7, 2023 at 21:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.