如果出现单例空指针异常,我猜你会这样写(因为我第一次这样写):
public class Test : MonoBehaviour
{
private static AStarManager instance = null;
public static AStarManager Instance
{
get
{
if (instance == null)
{
instance = new AStarManager();
}
return instance;
}
}
}
在你第二次使用单例时就会出现空指针异常,什么原因呢?
是因为继承MonoBehaviour和不继承MonoBehaviour的单例是不一样的,且大多数用的是不继承MonoBehaviour的单例
不继承的单例模式:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class baseManager<T> where T:new()
{
private static T instance;
public static T GetInstance()
{
//泛型类创建实例要写泛型约束new()
if (instance == null)
instance = new T();
return instance;
}
}
然后继承baseManager就可以使用了
public class AStarManager : baseManager<AStarManager>
{
//防止外部创建该实例
private AStarManager()
{
}
}
2.然后就是继承MonoBehaviour的情况:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//继承MonoBehaviour的单例模式对象,需要自己保证它的唯一性
public class SingleMono<T> : MonoBehaviour where T:MonoBehaviour
{
private static T instance;
public static T GetInstance()
{
//继承MonoBehaviour,不能new
//只能通过拖动脚本或者addcomponent,如果拖动多个脚本,就不是单例模式了
//所以自己实现
return instance;
}
protected virtual void Awake()
{
instance = this as T;
}
}
test.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class test : SingleMono<test>
{
protected override void Awake()
{
base.Awake();
}
// Start is called before the first frame update
void Start()
{
print(test.GetInstance().name);
}
}
第二种写法:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SingleAutoMono<T> : MonoBehaviour where T : MonoBehaviour
{
private static T instance;
public static T GetInstance()
{
if (instance == null)
{
GameObject obj = new GameObject();
obj.name = typeof(T).ToString();
DontDestroyOnLoad(obj);
instance = obj.AddComponent<T>();
}
return instance;
}
}
继承MonoBehaviour的单例,继承SingleMono的脚本只能挂载到一个物体身上,否则就不是单例了,这样就不是很好,而不继承MonoBehaviour的单例,不需要挂载,直接继承即可使用
对于多线程的情况:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class baseManager<T> where T:new()
{
private static T instance;
//定义标识让线程同步
private static readonly object locker = new object();
public static T GetInstance()
{
/*当第一个线程运行到这里,会对Locker对象加锁
当第二个运行到这里,检测到locker对象为加锁状态,该线程就会挂起等待第一个线程解锁
双重否定
*/
if(instance==null)
{
lock(locker)
{
//泛型类创建实例要写泛型约束new()
if (instance == null)
instance = new T();
}
}
return instance;
}
}