what is the different between string and new string ?

In c#

I had the line:

public string name;

But then the name had a green line under it.
The message was:
‘NPC.name’ hides inherited member ‘Object.name’. Use the new keyword if hiding was intended.

Then i used the Show potential fixes > Hide base member

Now the line is:

public new string name;

But what is that mean ? In other cases the message warning will be that the name is not assigned…

Change it to public string Name or _name.

This is one of the more confusing C# keywords, if for no other reason than it reuses an existing C# keyword (new) for a purpose that has absolutely nothing to do with the other meaning of the keyword:

 public GameObject g;
void Start() {
g = new GameObject("g"); // The more common usage of 'new'
}
public new string name; // The confusing usage

I’ve also never once came across a situation where the confusing version was actually useful, either.

As to what it actually does, is what the warning message says: it hides the inherited member. MonoBehaviour, which you’re inheriting from, already has a member called ‘name’ (in fact, ‘name’ goes all the way back to UnityEngine.Object). In MonoBehaviour, it returns the name of the script/class.

But then you go and declare a new member called ‘name’, and the compiler doesn’t know which ‘name’ you want. To prevent these ambiguous references, it wants you to explicitly say: “Anytime I use the word ‘name’, I’m referring to the one I created, not the one I inherited”. That’s what ‘new’ does in this context.

I find it useless because it makes confusing code. Consider this:

    public new string name;
    [ContextMenu("Name test")]
    void NameTest() {
        name = "fart";
        MonoBehaviour thingOne = GetComponent<YourScript>();
        YourScript thingTwo = GetComponent<YourScript>();
        Debug.Log (thingOne.name);
        Debug.Log (thingTwo.name);
    }

Now, thingOne and thingTwo obviously point to the same object, so this should output the same thing, twice, right? NOPE. Because thingOne is going to use MonoBehaviour’s .name, and thingTwo is going to use your .name. In my experience this sort of thing does nothing but cause really confusing errors. I can’t think of a situation where this is going to be the desired behavior.

So, anytime you’re tempted to use the ‘new’ keyword to hide an inherited member, don’t. Just use a different name. If you actually want to replace what .name does entirely, then use ‘override’ instead. (In the above scenario, you’d have to alter it to be a property with get/set functions, but it’d make both of the debugs output “fart”.)

3 Likes

I have actually found places where the ‘new’ keyword in the ‘confusing way’ actually does work out. But they’re VERY special use cases, and they’re also cases where… explaining the why it’s ok in that specific special situation is difficult if the person you’re explaining it to is novice.

It’s sort of like globals on crack. Globals are generally bad, but there’s cases where it’s good. You just need to know those cases. ‘new’ is like that, but its use cases are even slimmer.

I think a good example is something like this:

using System.Collections.Generic;

namespace com.spacepuppy.Collections
{

    /// <summary>
    /// Tests for equality based solely on if the references are equal. This is useful for UnityEngine.Objects that overrides the default Equals
    /// operator returning false if it's been destroyed.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ObjectInstanceIDEqualityComparer<T> : EqualityComparer<T> where T : UnityEngine.Object
    {
        private static IEqualityComparer<T> _defaultComparer;

        public new static IEqualityComparer<T> Default
        {
            get { return _defaultComparer ?? (_defaultComparer = new ObjectInstanceIDEqualityComparer<T>()); }
        }

        #region IEqualityComparer<T> Members

        public override bool Equals(T x, T y)
        {
            return GetHashCode(x) == GetHashCode(y);
        }

        public override int GetHashCode(T obj)
        {
            if (object.ReferenceEquals(obj, null)) return 0;
            return obj.GetInstanceID();
        }

        #endregion
    }
}

The class itself is an EqualityComparer for use in HashSet’s and Dictaionaries. It’s not really anything to do with why ‘new’ is useful here.

We’ll notice that the static ‘Default’ property is where I’ve used ‘new’.

This is because EqualityComparer already implements a static ‘Default’ property.

(of course, reading this… why isn’t is just implementing IEqualityComparer instead… I think there’s something I needed it to be an EqualityComparer explicitly, I can’t remember exactly. There was some weird place that this came up though… compatability with legacy junk)

BUT, because the usage of Defualt looks like this in either case:

var a = EqualityComparer<string>.Default
var b = ObjectInstanceIDEqualityComparer<Component>.Default

There’s none of that confusion going on. We’re forced to always be using the class’s explicit name anyways. You don’t expect both a and b to necessarily be the same thing.

Or another is like this:

    internal class WeakReference<T> : WeakReference where T : class
    {
        public static WeakReference<T> Create(T target)
        {
            if (target == null) return WeakNullReference<T>.Singleton;

            return new WeakReference<T>(target);
        }

        protected WeakReference(T target)
            : base(target, false)
        {

        }

        public new T Target
        {
            get { return base.Target as T; }
        }
    }

In this I create a WeakReference (because it doesn’t exist in the older version of mono in unity), and I want the ‘Target’ property to uncover the type as the generic type rather than as ‘object’.

Again, they both return the same object either way, just when we have it typed as WeakReference, we receive it cast as expected.

There is one other time that I use it as well, but it’s my more contentious use. I hate that it’s there, but I just can’t stand having it named anything else. And that is if I reimplement the now obsoleted component properties on a MonoBehaviour. Like ‘animation’ and ‘camera’. I have a small handful of components that explicitly deal with animation or cameras, and so having these properties make sense. And I couldn’t stand have a ‘Animation’ and ‘animation’ property one of which is obsolete. So I stuck a ‘new’ in… my heart isn’t so heavy about it because I know if you have it cast as MonoBehaviour, you expect it to be obsolete, it shouldn’t be there anyways. So when you have it as the explicit type where ‘new’ overrides, it should be there.

But these are just weird off cases where ‘new’ just happens to work. They’re few and far between, and usually the best judgement would be… use it if and only if you know its implications, and you know there’s no other way around using it.

2 Likes

What does it mean? It means it’s a good way to create bugs, so don’t do it unless you really really know what you’re doing. Even then, you might know what you’re doing today, but if you came back to that code 6 months from now? Bugs are likely to happen then.

As the above posters mentioned, just use a different name for, er, name.

The TL;DR is don’t use new in this way, ever. Instead rename the variable.

Slight correction, it returns the name of the GameObject its attatched to.

Blegh - this is a gross over-generalization and undercuts the great stuff in the post before it by @lordofduct
The original ask was what the difference was and the explanation in that post nails it.