【问题标题】:call base class method *WITHOUT* using override使用覆盖调用基类方法 *WITHOUT*
【发布时间】:2013-03-03 22:11:01
【问题描述】:

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

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

class someclass : MonoBehavior
{
}

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

void OnGUI()
{
  so something here
}

所以如果你说 5 个脚本都包含 OnGUI 函数,那么它会在所有 5 个脚本中被调用

我想自己实现这种类型的东西,但我想不通。

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

这是来自 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;
          }
    }
}

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

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

【问题讨论】:

  • 请用您的具体问题更新您的标题。阅读How to Ask
  • 听起来您可能正在寻找具有虚拟方法的抽象类。
  • 我不太明白你的问题是什么。如果你不懂 oop,我建议你阅读一些教程。
  • 我看过教程,都说这东西是不可能的

标签: c# subclass


【解决方案1】:

如果您不想/可以使用 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);
    }
}

【讨论】:

  • @CodeCaster - 问题与现有库有关,问题中的代码不会覆盖任何现有的基类方法。
  • OP 说:“我想自己实现这种东西,但我想不通。”
  • @CodeCaster - 问题询问如何在不使用 override 的情况下进行操作。
  • @Lee 啊,这就是我应该如何阅读问题的最后一行,谢谢。如果 EdW 更新答案,我可以撤回反对票,但我想指出 OP,这种设计有异味。
  • Unity Game 引擎有没有气味,我想做同样的事情,但是我发现的每个教程(包括 msdn)都说你必须使用 override,但 unity 并没有让我感到困惑跨度>
【解决方案2】:

由于它不使用虚方法,因此最有可能的方法是使用反射。 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]);
            }
        }
    }
}

【讨论】:

    【解决方案3】:

    您如何编写基类或实现或其他任何内容 在您的子类中调用预定义函数但不调用 需要函数的子类,而不必使用 覆盖它们?

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

    【讨论】:

    • 你仍然需要override他们
    • @ErnodeWeerd 我不确定你的评论?
    • 在 Unity 引擎中,您不要在任何地方使用 overid
    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      如果我得到你所说的,我认为你正在寻找的是一个具有继承的基类:

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

      【讨论】:

        猜你喜欢
        • 2011-11-03
        • 1970-01-01
        • 2011-12-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-10
        • 2018-08-01
        • 1970-01-01
        相关资源
        最近更新 更多