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";
    }
}
Eagle-Eye
  • 1,468
  • 2
  • 18
  • 26
  • 1
    You need something that can be *virtual* -- a *Property* ("Getter") or a *Method*. Member variables are *never* virtual. –  Jan 13 '12 at 01:11

6 Answers6

51

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";
    }
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 2
    @Eagle-Eye What would polymorphic variables do? Don't criticise the practice if you can't articulate the theory. – Jon Hanna Jan 13 '12 at 02:17
  • +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. – Adam Robinson Jan 13 '12 at 03:50
  • 2
    @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.) – Eagle-Eye Dec 28 '12 at 09:56
9

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"; }
    }
}
Adam Robinson
  • 182,639
  • 35
  • 285
  • 343
  • 1
    Though he probably wouldn't hardcode the values like that, it may vary. – Jeff Mercado Jan 13 '12 at 01:11
  • 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: http://stackoverflow.com/questions/1112458/c-sharp-member-variable-overrides-used-by-base-class-method – paulsm4 Jan 13 '12 at 01:14
  • 1
    @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). – Adam Robinson Jan 13 '12 at 01:15
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";
}
x3ro
  • 329
  • 1
  • 5
  • 11
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.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
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"; } }
}
Jesse Emond
  • 7,180
  • 7
  • 32
  • 37
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 :)