1

我试图弄清楚如何用 c# 做一些我特别注意到 Unity 引擎所做的事情。这似乎是某种形式的实现或子类化,但由于我没有我不知道的来源。

在 Unity 中,所有脚本都是这样的:

class someclass : MonoBehavior
{
}

现在有一个函数列表,您可以通过这个 MonoBehavior 在您的类中调用引擎来使用该引擎,例如

void OnGUI()
{
  so something here
}

因此,如果您说 5 个脚本都包含 OnGUI 函数,它将在所有 5 个脚本中调用

我想自己实现这种类型的东西,但我无法弄清楚。

您如何编写基类或实现或在子类中调用预定义函数但不需要函数的子类并且不必在其中使用覆盖的任何东西?

这是来自统一引擎的示例源文件:

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;
          }
    }
}

该代码运行良好,然后引擎调用在第一次启动时开始(单次调用)并调用更新每一帧通知绝对没有覆盖在任何地方的代码中

它似乎是某种事件系统,但我在谷歌上找不到任何描述如何做到这一点的东西。

4

5 回答 5

3

如果您不想/可以使用override关键字,您可以使用反射来做到这一点(可能使用dynamic关键字)

基类“简单地”在派生类中搜索特定的签名/属性并调用方法。

如果您自己编写此代码,请考虑缓存反射的结果(或使用dynamic可能为您进行缓存的关键字)并测试您是否仍然获得所需的性能。反射可能非常缓慢。也请参阅这个问题:Dynamic Lang。运行时与反射

例子:

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);
    }
}
于 2013-03-15T09:04:35.693 回答
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]);
            }
        }
    }
}
于 2013-03-15T09:23:27.210 回答
0

您如何编写基类或实现或在子类中调用预定义函数但不需要函数的子类并且不必在其中使用覆盖的任何东西?

据我了解,这些只是virtual方法。基类可能会定义一些基本实现,但不需要派生类来覆盖这些方法。

于 2013-03-15T09:05:24.770 回答
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
    }
}
于 2013-03-15T09:08:15.707 回答
0

使用virtualoverride

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防止基类本身的实例化。

于 2013-03-15T09:08:32.503 回答