我正在尝试使用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 ?!
}
答案 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:'默认值'不是'空值'。
参考文献:
我希望有帮助