Linq 简化过滤器
您可以使用 Linq OfType
进行过滤。
ISaveable[] saveables = FindObjectsOfType<MonoBehaviour>(true).OfType<ISaveable>().ToArray();
当然,首先还需要找到所有的对象。
请注意,这暴露了关于未激活游戏对象或禁用行为的FindObjectsOfType
的一般限制。(更新:在新的Unity版本中,可选的bool
参数使得包括未激活/禁用组件成为可能。)
现在也可以看到Object.FindObjectsByType
(仍然限于UnityEngine.Object
)
遍历层次结构
您可以扩展它以遍历场景中所有根级对象。这是有效的,因为GetComponentsInChildren
确实也适用于接口!
var saveables = new List<ISaveable>();
var rootObjs = SceneManager.GetActiveScene().GetRootGameObjects();
foreach(var root in rootObjs)
{
saveables.AddRange(root.GetComponentsInChildren<ISaveable>(true));
}
如果更有效率 - 是的,不是,可能,我不知道 - 但它也包括不活动和禁用的对象。
而且,可以扩展它以遍历使用多个已加载场景的对象。
var saveables = new List<ISaveable>();
for(var i = 0; i < SceneManager.sceneCount; i++)
{
var rootObjs = SceneManager.GetSceneAt(i).GetRootGameObjects();
foreach(var root in rootObjs)
{
saveables.AddRange(root.GetComponentsInChildren<ISaveable>(true));
}
}
一开始就不要使用接口
这种替代方案与this answer有些相似,但它有一个巨大的缺陷:您需要一个特定的接口实现才能使其工作,这无效了接口的整个概念。
因此,从评论中也可以看出一个重要问题:为什么要使用接口?
如果它只会用于MonoBehaviour
,那么您应该使用抽象类
。
public abstract class SaveableBehaviour : MonoBehaviour
{
public abstract void SaveData();
}
这已经完全解决了使用FindObjectsOfType
的问题,因为现在你可以简单地使用
SaveableBehaviour[] saveables = FindObjectsOfType<SaveableBehaviour>();
但是你仍然可以更进一步:为了实现更简单和更高效的访问,您可以使它们完全自行注册,而无需使用管理器或 Singleton 模式!为什么类型不应该直接处理其实例呢?
public abstract class SaveableBehaviour : MonoBehaviour
{
public abstract void SaveData();
private static readonly HashSet<SaveableBehaviour> instances = new HashSet<SaveableBehaviour>();
public static HashSet<SaveableBehaviour> Instances => new HashSet<SaveableBehaviour>(instances);
protected virtual void Awake()
{
instances.Add(this);
}
protected virtual void OnDestroy()
{
instances.Remove(this);
}
}
这样你就可以简单地继承
public class Example : SaveableBehaviour
{
public override void SaveData()
{
}
protected override void Awake()
{
base.Awake();
}
}
你可以通过以下方式访问该类型的所有实例
HashSet<SaveableBehaviour> saveables = SaveableBehaviour.Instances;
foreach(var saveable in saveables)
{
saveable.SaveData();
}
MonoBehaviour
?我知道C#是如何工作的;当然,这取决于具体的使用情况=>“如果它只会用于MonoBehaviour”,这就是我在句子中的开头部分。 - derHugo