C# - 重置类或结构

时间:2017-04-26 03:12:01

标签: c# unity3d struct nullable non-nullable

我正在尝试使用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 Scripting的内容,答案是:

  

结构不能为null,就像int不能为null一样,并且   float不能为null - 它们都是值类型

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

解决方案#1 我可以使用public bool hasSelected并在使用selected属性之前始终对此进行测试。

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

是否存在更好的解决方案,更清洁?!

奖金问题:如何基于测试创建一个返回单个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 ?!
 }

3 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:0)

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

有些时候,当程序需要一个结构并传递一个类时,你的程序可能会有不同的行为(或行为不当)。

以下是两种方法的更改:

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

答案 2 :(得分:0)

关于主要问题

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

关于选择/取消选择功能

我已经重构了你的代码以使用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:'默认值'不是'空值'。

参考文献:

我希望有帮助