C# - 重置 class 或结构上的结构值

C# - Reset the value of struct on class or struct

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

从基本代码开始:

 public class Engine : MonoBehaviour {

   public Hero selectedHero;
   public List<Hero> heroes;

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

首先我尝试为 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 ! :'(
}
/* ... */

我收到了这个错误:

Cannot convert null to Hero because it is a value type

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

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

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

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

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

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

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

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

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

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

如果有理由您应该使用 Struct 而不是 class ,那么请使用默认值来检查您的结构。

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

下面是您的两种方法的更改:

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

关于主要问题:

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

关于 select/unselect 函数

我已重构您的代码以使用结构:

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:'default value''Null Value'以外的

参考文献:

希望对你有所帮助