Reputation: 5148
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 ?!
}
Upvotes: 0
Views: 1173
Reputation: 11
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
Upvotes: 1
Reputation: 12745
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);
}
Upvotes: 0
Reputation: 12258
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;
}
}
Upvotes: 2