0

我正在尝试使用 Unity 编写一些脚本,但我在理解 struct 的工作原理方面遇到了一些问题。

从代码库开始:

 public class Engine : MonoBehaviour {

   public Hero selectedHero;
   public List<Hero> heroes;

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

首先,我尝试制作一些功能来选择/取消选择..

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

我得到了这个错误:

无法将 null 转换为,Hero因为它是值类型

我阅读了很多关于 C# 和 Unity 脚本的内容,答案是:

struct 不能为 null,就像 int 不能为 null,float 不能为 null - 它们都是值类型

但 ?什么是真正的解决方案!?我使用了两个丑陋的解决方案来避免这种情况:

解决方案#1我可以在使用属性public bool hasSelected之前放置一个并始终测试这个。selected

解决方案 #2如果长度为 0 或 1,则创建一个List<Hero> selected而不是简单的并处理。Hero

是否存在更好的解决方案,更干净?!

奖励问题:如何创建一个基于测试返回单个英雄的函数,我最好的(丑陋的)解决方案:

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

3 回答 3

2

如果您需要您的类型可以为空,听起来您应该创建Hero一个类(引用类型)而不是结构(值类型)。对代码的更改将是最小的,只需交换关键字:

public class Hero {
    public string name;
    public Hero(string n) {
        name = n;
    }
}
于 2017-04-26T03:45:24.563 回答
0

如果有理由你应该使用 Struct 而不是 class ,那么使用 default of 来检查你的结构。

有时,当您的程序需要一个结构并且您传递一个类时,它的行为(或行为不端)可能会有所不同。

因此,以下是您的两种方法的更改:

       public bool hasSelected(Hero h)
        {
            return !(h.Equals(default(Hero)));
        }
        public void clearSelected()
        {
            selectedHero = default(Hero); 
        }
于 2017-04-26T04:10:23.997 回答
0

关于主要问题

值类型(int、struct 等)不能以其二进制表示形式表示 null,这就是 .NET 不允许的原因。但是 .NET 它具有Nullable<T>为空表示添加额外字节的结构。

关于选择/取消选择功能

我已重构您的代码以使用 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);
}

关于奖金问题

这很简单,使用 LinQ =)

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

PS:“默认值”不是“空值”。

参考:

我希望这会有所帮助

于 2017-04-26T04:26:02.667 回答