我有一个问题,我知道如何在 C++ 中解决,但我不知道它在 C# 中如何工作。这是 C# 中的示例代码:
public class TowerTile<ScriptType, SpriteName> : Tile where ScriptType : MonoBehaviour {
private void Awake() {
gameObject = new GameObject();
gameObject.AddComponent<ScriptType>();
colliderType = Tile.ColliderType.None;
sprite = GameManager.shared.sprites[SpriteName];
}
}
SpriteName
该示例中的类型应为字符串,因此我可以在 operator[]
中使用它在 Dictionary<string, Sprite> sprites
.
以下是我用 C++ 编写的方法:
template <typename ScriptType, typename SpriteRef = std::string>
class TowerTile : public Tile {
private void Awake() {
gameObject = new GameObject();
gameObject.AddComponent<ScriptType>();
colliderType = Tile.ColliderType.None;
sprite = GameManager.shared.sprites[SpriteRef];
}
}
如何在 C# 中实现此目的?我无法将字符串作为构造函数参数传递,因为这些 Tile 对象是用 ScriptableObject.CreateInstance<T>()
实例化的,它不能传递任何构造函数参数。
最佳答案
为了让问题和答案更清楚,我想从示例中模板化这个类,因为它在 Unity 中用 ScriptableObject.CreateInstance<T>()
实例化的方式不允许构造函数参数。即使在 C# 中可以按值进行特化(这不是),它也无济于事,因为实例化方法无论如何都无法创建泛型类型(为什么是 Unity?)。所以我使用的解决方案是一个带有模板化方法的工厂,该方法返回基类“Tile”。
public class TileFactory {
private TileFactory() {}
public static Tile CreateInstance<ScriptType>(string spriteName) where ScriptType : DefaultAI {
var tile = ScriptableObject.CreateInstance<TowerTile>();
tile.sprite = GameManager.shared.sprites[spriteName];
tile.gameObject.name = spriteName;
tile.gameObject.GetOrAddComponent<ScriptType>();
return tile;
}
}
所讨论示例的变化是:
- 无法通过
spriteName
的问题进入ScriptableObject.CreateInstance<T>()
通过将此方法包装在我自己的工厂方法中来解决。 -
ScriptableObject.CreateInstance<T>()
使用非通用类型调用,并且仅在将通用类型脚本添加到对象之后。 - 返回的实例也是一种非泛型类型,因为某些原因,Unity 似乎存在一些问题。
-
ScriptType
现在应该是基地DefaultAI
这是基地MonoBehaviour
(与本答案的目的无关)。
另一种选择是使用 Buidler
但是因为我只需要传递 1 个必需的参数,builder 就没有多大意义了。在其他一些情况下,这将是更好的解决方案。
p.s.感谢 Furkan Kambay 提供相关资源帮助解决此问题
关于c# - Unity/C#:按值进行类特化(相当于 C++ std::array<int>),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48366181/