C#基础之构造函数

17 篇文章 0 订阅

构造函数的基础

我们构造对象的时候,对象的初始化过程是自动完成的,但是在初始化对象的过程中有的时候需要做一些额外的工作,例如需要初始化对象存储的数据,构造函数就是用于初始化数据的函数。

声明基本的构造函数的语法就是声明一个和所在类同名的方法,但是该方法没有返回类型。

public class MyClass{
    public MyClass()
     {
        这个构造函数的函数体
	}
}

 

当我们使用new关键字创建类的时候,就会调用构造方法。

我们一般会使用构造方法进行初始化数据的一些操作。

构造函数可以进行重载,跟普通函数重载是一样的规则

注意:当我们不写,任何构造函数的时候,编译器会提供给我们一个默认的 无参的构造函数,但是如果我们定义了一个或者多个构造函数,编译器就不会再提供默认的构造函数

例:

class Vector3
    {
        private float x, y, z;
        public Vector3()//定义了构造函数,系统自定的不会被调用了
        {
            Console.WriteLine("构造函数1被调用了");
        }
        public Vector3(int x, int y, int z)
        {
            Console.WriteLine("构造函数2被调用了");
            this.x = x;
            this.y = y;
            this.z = z;
        }
        public double length()
        {
           return Math.Sqrt(x * x + y * y + z * z);
        }
   }
   static void Main(string[] args)
    {
        Vector3 v1 = new Vector3();
        Vector3 v2 = new Vector3(1,2,3);
        Console.WriteLine(v2.length());
        Console.ReadKey();
    }

 构造函数中将常遇到的bug

在实现功能时,常常遇到了一个bug,代码如下:

 public class EnemySpawn: MonoBehaviour
    {
        private EnemySpawn()
        {

        }
        private static EnemySpawn _instance = null;
        public static EnemySpawn Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new EnemySpawn();
                return _instance;
            }
        }
    }

现在实现一个敌人产生器的类,将其写作单例模式。

在调试过程中会发现,在Instance的get中,即便new EnemySpawn(),__instance单例对象仍然为null??!!

    public class TestManager: MonoBehaviour
    {
        public TestManager()
        {
            Debug.Log("You call me in TestManager");
        }
    }

当开始运行游戏时,Log输出了两次”You call me in TestManager”.

注意注意:

永远不要在继承MonoBehaviour的类中预设构造函数的调用

其实,在Unity的文档中有提到上述问题:

“避免使用构造函数 不要在构造函数中初始化任何变量,使用Awake或Start实现这个目的。即使是在编辑模式中Unity也自动调用构造函数,这通常发生在一个脚本被编译之后,因为需要调用构造函数来取向一个脚本的默认值。构造函数不仅会在无法预料的时刻被调用,它也会为预设或未激活的游戏物体调用。

实际上,MonoBehaviour有两个生命周期,一个是作为C#对象的周期,一个是作为Component的周期。构造函数代表第一个,Awake代表第二个。Editor环境下Editor的代码和脚本代码在同一个AppDomain里,对象的生命周期会表现的跟Player环境下不一样。比如Editor中构造函数被调用的次数和时机跟build出来的游戏不一样,这样就不容易保证正确性。

而且,在编辑器模式下,脚本类就会被构造,在你进入游戏之后,也会被构造,你无法预期类的构造函数何时被调用,因此,凡是继承自MonoBehaviour的类,把它的Awake或者Update当做构造函数来初始化变量。

那么改造过后的代码如下:

public class EnemySpawn: MonoBehaviour {
       #region singleton
    private EnemySpawn() {}
    private static EnemySpawn_instance = null;
    public static EnemySpawn Instance {
        get {
            return _instance;
        }
    }
    #endregion

    private void Awake() {
        _instance = this;
    }
}

这样只是对它的可访问性进行了限制,并没有使用new EnemySpawn()。

但是,这种单例实现有个缺陷,就是你必须这种将脚本手动赋给一个GameObject(缺陷)。

public class Singleton<T> : MonoBehaviour where T : 
MonoBehaviour{
private static T instance;
public static T Instance {
    get {
        if(instance == null){
            GameObject obj = new GameObject();
            instance = obj.AddComponent<T>();
            obj.name = typeof(T).Name;
            //切换场景之后不销毁单例对象
            DontDestroyOnLoad(obj);
        }
        return instance;
    }
}


public class AudioManager : Singleton<AudioMananger>
{
    //
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值