Coding漫谈 | 唠唠C#覆写

admin 2024年11月4日09:39:36评论15 views字数 3974阅读13分14秒阅读模式

最近因为一些原因又开始写C#了,以前一直认为C#就是microsoft版java(这两家已经打了很多年了不要审判我这个脚本小子),现在认真写写还是能发现不少不同的。作为一个备案,还是记录一下编程过程中遇到的一些_feature_,一家之见,不喜勿喷哈。

另:这些天要开始尝试新的文章风格(不是路线),请各位读者海涵。

特色关键字

我们知道在继承与抽象中Java只有表示抽象的abstract和表示继承的extend(接口不算)。

在C#中则有virtual、abstract两个表示抽象的关键字;new和override两个表示覆写的关键字,继承则使用“:”冒号。

这两种方式的高下之分我就不评价了,反正这俩语言也不是只互掐过一次两次- -。

Coding漫谈 | 唠唠C#覆写

对于所有要覆写的函数,C#都建议使用override表示;而被覆写的变量则推荐使用new表示。

除此之外,virtual关键字为C#中较有特色的一个关键字。关于它的作用我们会用一系列代码来表示。

抽象与继承

首先作为对比我们来写一个Java抽象类(new的方式请不要在意,为了不建工程写的):

public class A{


    public static void main(String args[]){
        C c=new A().new C();
        c.funa();
        c.funb();
        c.func();
    }

    public abstract class B{
        public String a="B.a";
        public abstract void funa();

        public void funb(){
            System.out.println("B.funb");
        }
    
        public void func(){
            System.out.println("B.func");
        }
    } 

    public class C extends B{
        public void funa(){
            System.out.println(this.a);
        }
    
        public void funb(){
            super.funb();
            System.out.println("C.funb");
        }
    
    }

}

输出为:

Coding漫谈 | 唠唠C#覆写

可以看到Java采用了很智能的方式,同名方法自动重载且不会调用父类中的方法,无覆盖方法自动调用父类。当类C的一个方法被调用时,若其本身存在同名方法则执行本身的方法,若不存在则向上查找父类的方法并执行。

然后我们可以写一个类似的C#类:

using System;

public class A
{
    public abstract class B
    {
        public string a = "B.a";
        public abstract void funa();
        public void funb()
        {
            Console.WriteLine("B.funb");
        }
        public virtual void func()
        {
            Console.WriteLine("B.func");
        }
        public void fund()
        {
            Console.WriteLine("B.fund");
        }
    }

    public class C : B
    {
        public override void funa()
        {
            Console.WriteLine(a);
        }
        public new void funb()
        {
            Console.WriteLine("C.funb");
        }
        public override void func()
        {
            Console.WriteLine("C.func");
        }
    }

    public static void Main()
    {
        C c = new C();
        c.funa();
        c.funb();
        c.func();
        c.fund();
    }
}

输出为:

Coding漫谈 | 唠唠C#覆写

这里由于中间插了一个virtual方法c导致结果看上去有些不同,但其实除开c方法输出是一样的。单纯从这里看来,也许读者会认为C#和Java的继承除了书写上稍有不同(比如强调你添加override或new,不过其实不添加也是可以过编译的),其它地方也没有很大的差别(override和new我没啥需求就不讲了,它俩也是不大一样的)。

Coding漫谈 | 唠唠C#覆写

但我们还有一个virtual关键字呢。

Virtual函数

这次我们从父类来执行函数。

Java中其余内容不变,B类的func改成调用funb,main函数中只调用new C().func():

public static void main(String args[]){
    C c=new A().new C();
    c.func();
}
...
public void func(){
    this.funb();
}

再次执行:

Coding漫谈 | 唠唠C#覆写

可以看到父类和子类的funb都已经执行了。

Java先从C中寻找func->不存在->向父类B寻找func->调用funb->调用B.funb->调用C.funb。

而C#中呢?首先我们需要知道的是C#中不标virtual和abstract的函数是不可以覆写的。所以不会存在普通函数覆写的执行顺序一说。abstract函数没有函数体,只需要看virtual。

同样的将父类中的fund改成调用func,输出如下:

Coding漫谈 | 唠唠C#覆写

可以看到只执行了子类的virtual函数。事实上,无论C#中有多少覆写关系,最后被调用的永远只会有当前调用函数。例如,上文中的派生类C,如果我们如此调用:

C c = new C();
(B)c.func();

那么被调用的应当是B中的func。而如果没有前面的类型转换,调用的则是C中的func。

Virtual特性的应用

这又要说到笔者为啥要写这篇文章:主要还是因为在实际使用中遇到了virtual函数的好处,也顺带吃了一嘴C#特性的亏- -。

假设我有一个抽象类Abs_selectable,派生出抽象类Abs_componment,再从Abs_componment中派生出两个不同的类Obj_a和Obj_b。

然后存在以下情况:

Abs_componment中有一个监听器函数onTrigger,由于所有子类都需要监听这个事件,所以我在监听器函数中调用一个virtual函数on_trigged,然后将监听器函数本身设置为普通函数。在on_trigged中先做default操作,再在子类中根据不同情况进行覆写,当需要覆写时直接override即可。而对于需要都实现的部分(比如在父类的相同过程上再次扩展)只需要调用一次base.func()即可。在调用时,虽然都调用的是父类的监听函数,但父类的virtual方法会根据情况进行调用,避免多次调用不必要函数的问题。

当然,说这一大堆嘴皮子还是不够形象,我用代码打个比方(这里没有遵循C#推荐的函数书写方式,只是个人习惯原因)。

父类Abs_device,实现virtual方法do_execute用于执行监听器函数:

public abstract class Abs_device : Abs_componment
{
    public virtual void do_execute(Mono_ray ray) 
    {
        ...
    }
    
    public void OnTriggerEnter2D(Collider2D d)
    {
        if....
        then:
            this.do_execute(ray);
    }
}

子类Device_rotate,不需要实现监听器函数,但在满足前置条件时会调用自己的逻辑do_entering:

public class Device_rotate : Abs_device
{
    public override void do_entering(Mono_ray ray)
    {
        ...
    }
}

子类,Device_normal,甚至可以什么都不实现,它会自动调用父类的处理方式:

public class Device_rotate : Abs_device {}

这样的多态私以为是更为合理的。

Coding漫谈 | 唠唠C#覆写

. . . * . * 🌟  * . * . . .

由于很多人问我微信群的事情,所以我建了一个小微信群。现在可以在公众号菜单里选择合作交流->交流群获取交流群二维码,希望大家和谐交流,为更好更友善的行业环境贡献自己的力量。

如果喜欢我的文章,请点赞在看。网安技术文章、安卓逆向、渗透测试、吃瓜报道,尽在我的公众号:

原文始发于微信公众号(重生之成为赛博女保安):Coding漫谈 | 唠唠C#覆写

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年11月4日09:39:36
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Coding漫谈 | 唠唠C#覆写https://cn-sec.com/archives/3351794.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息