0

I'm trying to code some script with Unity, and I have some issue to understand how struct works.

Start with a base of code:

 public class Engine : MonoBehaviour {

   public Hero selectedHero;
   public List<Hero> heroes;

   public struct Hero {
     public string name;
     public Hero(string n) {
       name = n;
     }
   }
 } 

First I try to make some function to select/unselect..

/* ... */
public Hero getSelected(Hero h) {
  return selectedHero;
}
public void setSelected(Hero h) {
  selectedHero = h;
}
public bool hasSelected(Hero h) {
  return (selectedHero != null);
}
public void clearSelected() {
  selectedHero = null; //  This is not working ! :'(
}
/* ... */

And I got this error:

Cannot convert null to Hero because it is a value type

I read a lot's about C# and Unity Scripting and the answer is:

A struct can't be null in the same way that an int can't be null, and a float can't be null - they're all value types

But ? What's the real solution !? I used two ugly solution to avoid this:

Solution #1 I can put a public bool hasSelected and always test this one before use the selected attribute.

Solution #2 Is to create a List<Hero> selected instead of simple Hero and handle if the Length is 0 or 1.

Does exist a better solution, more clean ?!

Bonus question: How to create a function who return a single Hero based on a test, my best (ugly) solution:

public Hero GetHero(string name) {
    foreach (Hero hero in heroes) {
        if (hero.name == name) {
            return hero;
        }
    }
    return null; // Not working ?! What can I return ?!
 }
eli-bd
  • 1,533
  • 2
  • 17
  • 35
Arthur
  • 4,870
  • 3
  • 32
  • 57
  • 2
    Is there anything barring you from just making this a class? (Is there a specific reason you need this type to be a struct?) If there is some requirement, perhaps you could just make `selectedHero` a nullable with `Hero?`. Then check `.HasValue` whenever you plan to use it. – Serlite Apr 26 '17 at 03:22
  • Humm I'm a JS boy.. So I don't really know. If I use a class for Hero it work the same way but I can set it to null ? – Arthur Apr 26 '17 at 03:27
  • 1
    If you need an instance of a type to have a null (and not just default) value, then you probably want to use a class instead of a struct. Just swapping the keyword should be (mostly) enough. – Serlite Apr 26 '17 at 03:30
  • Okay I understand, struct is kind of used to return multiple data. And class can be defined under another class (like here `Engine.Hero`) or it's better to set a new class by is own ? – Arthur Apr 26 '17 at 03:32
  • Well...if you plan to reference the class in many other scripts, you might want to make it separately. (Unless it's very tightly coupled with its parent class.) – Serlite Apr 26 '17 at 03:41
  • I understand now, thank you Serlite. Can you make a quick answer to be able to close this question? – Arthur Apr 26 '17 at 03:42
  • Glad I could help out! – Serlite Apr 26 '17 at 03:45

3 Answers3

2

If you need your type to be nullable, it sounds like you should make Hero a class (reference type) instead of a struct (value type). The changes to your code will be minimal, just swap the keyword:

public class Hero {
    public string name;
    public Hero(string n) {
        name = n;
    }
}
Serlite
  • 12,130
  • 5
  • 38
  • 49
1

About main question:

Value types (int, struct, etc..) cannot express null in its binary representation, that's why .NET does not allow. But the .NET it has the Nullable<T> struct that add extra bytes for null representation.

About select/unselect functions

I have refactored your code to work with struct:

public Hero GetSelected()
{
    return selectedHero;
}

public void SetSelected(Hero h)
{
    selectedHero = h;
}

public bool HasSelected()
{
    return !(selectedHero.Equals(default(Hero)));
}

public void ClearSelected()
{
    selectedHero = default(Hero);
}

About bonus question:

That's simple, use LinQ =)

public Hero GetHero(string name)
{
    return heroes.Where(w => w.name.Equals(name)).FirstOrDefault();
}

PS: The 'default value' It is other than 'Null Value'.

References:

I hope that helps

crisdut
  • 11
  • 1
0

If there is a reason you should be using Struct instead of class , then use default of to check your structs.

Some times your program may behave (or mis-behave) differently when it expects a struct and you pass a class.

So here are the changes for two of your methods:

       public bool hasSelected(Hero h)
        {
            return !(h.Equals(default(Hero)));
        }
        public void clearSelected()
        {
            selectedHero = default(Hero); 
        }
Simsons
  • 12,295
  • 42
  • 153
  • 269