J'essaie de coder un script avec Unity et j'ai un problème pour comprendre le fonctionnement de struct.

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;
     }
   }
 } 

J'essaie d'abord de créer 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'ai eu cette erreur:

Impossible de convertir null en Hero car il s'agit d'un type valeur

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

Un struct ne peut pas être nul de la même manière qu'un int ne peut pas être nul, et un float ne peut pas être nul - ce sont tous des types valeur

Mais ? Quelle est la vraie solution!? J'ai utilisé deux solutions laides pour éviter cela:

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

Solution n ° 2 consiste à créer un List<Hero> selected au lieu d'un simple Hero et à gérer si la longueur est 0 ou 1.

Existe-t-il une meilleure solution, plus propre?!

Question bonus: Comment créer une fonction qui retourne un seul héros en fonction d'un test, ma meilleure (moche) 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 ?!
 }
0
Arthur 26 avril 2017 à 06:12

3 réponses

Meilleure réponse

Si vous avez besoin que votre type soit nullable, il semble que vous deviez faire de Hero une classe (type de référence) au lieu d'une structure (type valeur). Les modifications apportées à votre code seront minimes, échangez simplement le mot clé:

public class Hero {
    public string name;
    public Hero(string n) {
        name = n;
    }
}
2
Serlite 26 avril 2017 à 03:45

À propos de la question principale :

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

À propos des fonctions de sélection / désélection

J'ai refactoré 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);
}

À propos de la question bonus :

C'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 différente de la «valeur nulle».

Les références:

J'espère que ça aide

0
crisdut 26 avril 2017 à 04:26

S'il y a une raison pour laquelle vous devriez utiliser Struct au lieu de class, utilisez default of pour vérifier vos structures.

Parfois, votre programme peut se comporter (ou mal se comporter) différemment 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
Simsons 26 avril 2017 à 04:10