我正在试图弄清楚如何用c#做一些我特别注意到的Unity 引擎呢。它似乎是某种形式的实现或子类化,但因为我没有源,我不知道。
Unity中的所有脚本都是这样的:
class someclass : MonoBehavior
{
}
现在有一个函数列表,您可以通过此MonoBehavior调用引擎在您的类中调用,例如
void OnGUI()
{
so something here
}
所以,如果您说5个脚本都包含OnGUI函数,那么它将在所有5个脚本中调用
我想自己实现这种类型的东西,但我无法理解这一点。
如何编写基类或实现,或者这是什么,它调用子类中的预定义函数,但不需要函数的子类,而不必在其中使用override ?
这是来自unity Engine的示例源文件:
public class EnemyAttack : MonoBehaviour {
// Use this for initialization
void Start () {
AttackTimer = 0;
CoolDown = 2.0f;
}
// Update is called once per frame
void Update () {
if (AttackTimer > 0) AttackTimer -= Time.deltaTime;
if (AttackTimer < 0) AttackTimer = 0;
if (AttackTimer == 0){
Attack();
AttackTimer = CoolDown;
}
}
}
该代码完美运行,然后引擎调用在第一次启动时启动(单次调用)并且每次框架通知都会调用Update ,并且在任何地方都没有覆盖
它是某种事件系统,但我在谷歌上找不到任何描述如何执行此操作的内容。
答案 0 :(得分:3)
如果您不想/可以使用override
关键字,则可以使用反射(可能使用dynamic
关键字)来执行此操作
基类'简单'在派生类中搜索特定的签名/属性并调用方法。
如果您自己编写,请考虑缓存反射的结果(或使用可能为您执行缓存的dynamic
关键字)并测试您是否仍然获得所追求的性能。反思可能非常缓慢。也请看这个问题:Dynamic Lang. Runtime vs Reflection
示例:
class TheBehavior
{
public void Act()
{
dynamic derived = this;
try
{
derived.Foo(42);
derived.Foob(43);
}
catch (RuntimeBinderException e)
{
Console.WriteLine("Method call failed: " + e.Message);
}
}
}
class TheDerived : TheBehavior
{
public void Foo(int bar)
{
Console.WriteLine("Bar: " + bar);
}
}
class Program
{
static void Main(string[] args)
{
TheBehavior behavior = new TheDerived();
behavior.Act();
Console.ReadKey(true);
}
}
答案 1 :(得分:1)
由于它不使用虚方法,最可能的方法是使用反射。 MonoBehavior
类将反映其子类并搜索名称与正确模式匹配的方法:
public class MonoBehavior
{
private void InitSubclass()
{
var methods = new[] { "OnGUI", "OnLoad" }; //etc
foreach (string methodName in methods)
{
MethodInfo method = this.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
if (method != null)
{
method.Invoke(this, new object[0]);
}
}
}
}
答案 2 :(得分:0)
如何编写基类或实现或其他任何内容 它调用子类中的预定义函数但不调用 要求子类的功能,而不必使用 覆盖它们?
据我所知,这些只是virtual
方法。基类可以定义一些基本实现,但不要求派生类覆盖这些方法。
答案 3 :(得分:0)
如果我得到你所说的话,我认为你正在寻找的是一个带继承的基类:
public class BaseClass // or abstract
{
public void foo(int x)
{
//your implementation
}
}
public class ChildClass : BaseClass
{
public void foo(int x) : base(x)
{
//your implementation
}
}
答案 4 :(得分:0)
使用virtual
和override
。
class Program
{
static void Main(string[] args)
{
MyBaseClass ext1 = new Ext1();
ext1.DoSomething();
MyBaseClass ext2 = new Ext2();
ext2.DoSomething();
Console.ReadKey(true);
}
}
class MyBaseClass
{
public void DoSomething()
{
DoSomethingBase();
}
protected virtual void DoSomethingBase()
{
Console.WriteLine("DoSomethingBase");
}
}
class Ext1 : MyBaseClass
{
}
class Ext2 : MyBaseClass
{
protected override void DoSomethingBase()
{
Console.WriteLine("Overridden DoSomethingBase");
}
}
Ext1
类不会覆盖基类的行为,因此使用基类中的DoSomethingBase()
。 Ext2
会覆盖基本方法,因此会调用重写的方法。此代码打印:
DoSomethingBase Overridden DoSomethingBase
MyBaseClass
类也可以标记为abstract
,以防止实例化基类本身。