2017-04-26 2 views
0

J'essaye de coder un script avec Unity, et j'ai un problème pour comprendre comment fonctionne struct.C# - Réinitialise la valeur de struct sur la classe ou la structure

Commencez avec une base de code:

public class Engine : MonoBehaviour { 

    public Hero selectedHero; 
    public List<Hero> heroes; 

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

D'abord, j'essayer de faire une fonction pour sélectionner/désélectionner ..

/* ... */ 
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 ! :'(
} 
/* ... */ 

Et j'eu cette erreur:

Cannot convert null to Hero because it is a value type

J'ai lu beaucoup sur C# et Unity Scripting et la réponse est:

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

Mais? Quelle est la vraie solution!? J'ai utilisé deux solution pour éviter ce laid:

Solution # 1 je peux mettre un public bool hasSelected et toujours tester celui-ci avant d'utiliser l'attribut selected.

Solution # 2 est de créer un List<Hero> selected au lieu de simples Hero et la poignée si la longueur est 0 ou 1.

existe-t-une meilleure solution, plus propre!

question Bonus: Comment créer une fonction qui retourne un seul héros basé sur un test, ma meilleure solution (laid):

public Hero GetHero(string name) { 
    foreach (Hero hero in heroes) { 
     if (hero.name == name) { 
      return hero; 
     } 
    } 
    return null; // Not working ?! What can I return ?! 
} 
+2

Est-ce que vous empêchant de faire juste cette classe? (Y at-il une raison spécifique pour laquelle vous avez besoin que ce type soit une structure?) S'il y a une exigence, peut-être pourriez-vous simplement rendre 'selectedHero' un nullable avec' Hero? '. Ensuite, vérifiez '.HasValue' quand vous prévoyez de l'utiliser. – Serlite

+0

Humm Je suis un garçon JS .. Donc, je ne sais pas vraiment. Si j'utilise une classe pour Hero, ça fonctionne de la même façon mais je peux le mettre à null? – Arthur

+1

Si vous avez besoin d'une instance d'un type pour avoir une valeur null (et pas seulement par défaut), alors vous voulez probablement utiliser une classe au lieu d'une struct. Juste échanger le mot-clé devrait être (assez) assez. – Serlite

Répondre

2

Si vous avez besoin de votre type d'être annulable, il semble que vous devriez faire Hero une classe (type de référence) au lieu d'un struct (type de valeur). Les modifications apportées à votre code seront minimes, échanger simplement le mot-clé:

public class Hero { 
    public string name; 
    public Hero(string n) { 
     name = n; 
    } 
} 
0

S'il y a une raison pour laquelle vous devez utiliser struct au lieu de la classe, utilisez par défaut pour vérifier vos struct.

Il est possible que votre programme se comporte différemment (ou se comporte mal) lorsqu'il attend une structure et que vous passez une classe.

Voici donc les changements pour deux de vos méthodes:

 public bool hasSelected(Hero h) 
     { 
      return !(h.Equals(default(Hero))); 
     } 
     public void clearSelected() 
     { 
      selectedHero = default(Hero); 
     } 
+0

Qu'est-ce que je gagne pour utiliser struct pour des éléments tels que Héros, Bâtiments ou Objets? – Arthur

+0

Que voulez-vous dire par "Win to use"? – Simsons

0

A propos principale question:

types de valeur (int, struct, etc ..) ne peut pas exprimer nulle dans sa représentation binaire , c'est pourquoi .NET ne permet pas. Mais le .NET a la structure Nullable<T> qui ajoute des octets supplémentaires pour la représentation nulle.

A propos des fonctions select/unselect

Je refondus votre code pour travailler avec 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); 
} 

A propos de la question bonus:

qui est simple, utilisez LinQ =)

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

PS: La 'valeur par défaut' Elle est autre que 'Valeur nulle'.

Références:

J'espère que ça aide