实现C#委托/事件
- 声明的委托与时间&通知者执行的方法参数类型要匹配
- 参数声明要继承EventArgs
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1
{
//声明一个委托
public delegate void TimeEventHandler(object obj, TimeEventArgs args);
class Program
{
static void Main(string[] args)
{
Clock clock = new Clock(); //实例化一个时钟
MyClassEventHandler tehc = new MyClassEventHandler(); //实例化一个观察者类
//将事件跟我们定义的观察者进行连接
//这样,clock就会知道,每当TimeChanged事件被触发,就会去通知这个观察者
//注意我们连接的时候使用的并不是直接的观察者类实例中的ShowTime()方法
//而是一个委托,并在这个委托中传递ShowTime()方法,这也是"委托"的真正意义所在:
//我有一个方法,但我委托你来帮我关联到事件,因为事件只会直接跟委托打交道,
//而不是观察者的具体某个方法
clock.TimeChanged += new TimeEventHandler(tehc.ShowTime);
clock.go();
}
}
//TimeEventArgs是我们自己定义的一个类,用于保存事件中的参数.这里我们分别保存时间的时分秒
public class TimeEventArgs:EventArgs
{
private int hour;
private int minute;
private int second;
public TimeEventArgs(int hour,int minute,int second)
{
this.hour = hour;
this.minute = minute;
this.second = second;
}
public int Hour{
get {
return this.hour;
}
}
public int Minute {
get {
return this.minute;
}
}
public int Second {
get {
return this.second;
}
}
}
//观察者类,它有一个符合我们上面定义的"委托"的方法
//也就是void ShowTime(object obj,TimeEventArgs args)
//从这个方法的定义可以看到,我们只会关心返回类型和方法的参数,而方法名称则无所谓
class MyClassEventHandler
{
public void ShowTime(object obj,TimeEventArgs args)
{
Console.WriteLine("现在时间:"+args.Hour+":" + args.Minute + ":" + args.Second);
}
}
//时钟类
class Clock
{
//我们在这个类中定义了一个"TimeChanged"事件,注意其前面有两个关键字"event"和"TimeEventHandler"
//其中event表示这是一个事件,而不是方法或属性,TimeEventHandler则指出,谁要监听TimeChanged事件,它就必须有一个符合TimeEventHandler(委托)的方法
public event TimeEventHandler TimeChanged;
public Clock()
{
//注意,这里的null的含义是指TimeChanged事件当前还没有观察者关注它
//如果某个观察者要关注TimeChanged事件,它必须要让这个事件知道,方法是使用操作符"+="来借助委托将其加载到事件上
TimeChanged = null;
}
//时钟开始走动,我们的目标是每秒钟触发一次TimeChanged事件
public void go()
{
DateTime initi = DateTime.Now;
int h1 = initi.Hour;
int m1 = initi.Minute;
int s1 = initi.Second;
while (true)
{
DateTime now = DateTime.Now;
int h2 = now.Hour;
int m2 = now.Minute;
int s2 = now.Second;
if (s2 != s1)
{
h1 = h2;
m1 = m2;
s1 = s2;
//首先建立一个TimeEventArgs对象来保存相关参数,这里是时分秒
TimeEventArgs args = new TimeEventArgs(h2, m2, s2);
//注意这种写法,这一句是用来触发事件,事件不是类,所以不用使用"new"关键字,而且我们看到,这里TimeChanged的两个参数跟我们的委托(TimeEventHandler)是一致的
//其中第一个参数是触发这个事件的对象,我们这里使用的是一个时钟实例(this)
//clock.go() -> this就是clock变量的地址
TimeChanged(this, args);
}
}
}
}
}
delegate:
//实现一个委托
public delegate void myDelegate(int num);
public myDelegate m_delegate;
m_delegate += MyFun;
public void MyFun(int num)
{
Debug.Log("my func: " + num);
}
//delegate可以使用"="将所有已经订阅的取消
m_delegate = MyFun1; //MyFun订阅被取消,只有MyFun1在订阅中
Event:
public event myDelegate m_event;
m_event += MyFun;
m_event = MyFun; //错误
EventHandler:
//这是它的定义
//@sender: 引发事件的对象
//@e: 传递的参数
public delegate void EventHandler(object sender, EventArgs e);
//使用
public event EventHandler m_event; //修改自定义委托类型为EventHandler
Action:
//Action是系统预定义的一种委托,无返回值,参数在<>中传入
public Action<int> m_action;
//Compare:
public delegate void myDelegate(int num);
public Action<int> m_action;
//1,Action省略了void,因为它本身就是无返回值
//2, Action的参数在<>中定义的,delegate就是传统定义
//3,delegate要用关键字,然后自定义一个委托名字。而Action委托名字已定。不需要delegate关键字。
Interface:
用法:多继承
C#中接口可以多继承,接口之间可以互相继承和多继承。 普通类和抽象类可以继承接口。 一个类可以同时继承一个类和多个接口,但是接口不能继承类
interface Interface1(){
//接口方法不需要实现
void methodPrint1();
}
interface Interface2(){
void methodPrint2();
}
class BaseClass : Interface1, Interface2
{
public override void methodPrint1()
{
}
public override void methodPrint2()
{
}
}
class BaseClass2: Interface2
{
public override void methodPrint2()
{
}
}
Example:
public delegate void myDelegate(int num);
public class Event :MonoBehaviour
{
private void Start(){
DelegateFunc();
EventFunc();
EventHandlerFunc();
ActionFunc();
}
//delegate
public myDelegate m_delegate;
void DelegateFunc(){
m_delegate += MyEventFun;
m_delegate(1);
m_delegate = (d) =>{
Debug.Log("m_delegate : " + d);
};
m_delegate(2);
}
//Event
public event myDelegate m_event;
void EventFunc(){
m_event += MyEventFun;
m_event(3);
m_event = (d) =>{Debug.Log("m_event : " + d);};
m_event(4);
}
//EventHandler
public event EventHandler m_EventHandle;
void EventHandlerFunc(){
m_EventHandle += MyEventFun;
m_EventHandle(5, new EventArgs());
m_EventHandle += (o, e) =>{ Debug.Log("m_EventHandle: " + Convert.ToInt32(o) + "\t " + e.ToString());};
m_EventHandle(6, new EventArgs());
}
//Action 只需要申明参数即可,直接调用Action对象,即可调用到响应函数。Action最好用一个单例类管理
public Action<int> m_action;
void ActionFunc(){
m_action += MyEventFun;
m_action(7);
m_action = (d) =>{Debug.Log("m_action : " + d);};
m_action(8);
}
public void MyEventFun(int num)
{
Debug.Log("my func1: " + num);
}
public void MyEventFun(object sender, EventArgs e)
{
Debug.Log("my func2: " + Convert.ToInt32(sender) + "\t " + e.ToString());
}
}
可复用代码:
public static class GameEventDefine
{
public static Action Event_OnSelectNextPlayer;
public static Action Event_OnSelectPrePlayer;
public static Action<bool> Event_OnShowSelectCharacter;
}
private void Start()
{
GameEventDefine.Event_OnSelectPrePlayer += OnSwitchPlayerPre;
GameEventDefine.Event_OnSelectNextPlayer += OnSwitchPlayerNext;
GameEventDefine.Event_OnShowSelectCharacter += OnShowChacterSelectScene;
}
private void OnSwitchPlayerNext()
{
mCurSelectPlayerIndex++;
if (mCurSelectPlayerIndex >= mTotalSelectPlayerCount)
mCurSelectPlayerIndex = 0;
SetPlayerIndex(mCurSelectPlayerIndex);
}
private void OnSwitchPlayerPre()
{
mCurSelectPlayerIndex--;
if (mCurSelectPlayerIndex < 0)
mCurSelectPlayerIndex = mTotalSelectPlayerCount - 1;
SetPlayerIndex(mCurSelectPlayerIndex);
}
private void SetPlayerIndex(int index)
{
YXUnityLog.LogInfo(TAG, $"SetPlayerIndex index: {index}");
float xvalue = index * 5;
mTrsSelectRoot.transform.localPosition = new Vector3(xvalue, 0f, 0f);
}
public void OnShowChacterSelectScene(bool show)
{
mRoot.SetActive(show);
}
序列化
-
C#序列化和Unity序列化:
-
- 序列化是.NET运行时环境用来支持用户定义类型的流化的机制,目的是以某种存储形式使自定义对象持久化,或者将这种对象从一个地方传输到另一个地方。
- 在Unity中比较直观的理解就是面板可以看到的数据都是序列化成功的数据
-
序列化使用场景:
-
- Unity中需要在控制面板挂载但是不被其他类引用的时候(防止滥用public)
- C#中需要保存的数据(存储为二进制文件或者.xml文件)
-
Unity和C#用起来感觉有区别的原因是Unity Editor本身就是基于序列化的可视化窗口,所以他们底层目的还是相同的
-
例子
public class Test :Monobehavior
{
public int a; //序列化,显示
private int b; //不序列化,不显示
[SerializeField] int c; //序列化,显示
[HideInInspector] public int d; //序列化,不显示
[NonSerialized] public int e; //不序列化,不显示
public Test2 test2; //序列化,显示(可序列化的部分)
}
[Serializable]
public class Test2
{
public int aa;
private int bb;
}
//.NET环境下,序列化就是把自定义数据类型持久化并可以转换成二进制文件传输
[Serializable]
public class DemoClass
{
public int _id;
public string _myName;
public DemoClass(int id, string myName)
{
_id = id;
_myName = myName;
}
public DemoClass()
{
}
public void Output()
{
Debug.LogError(_id);
Debug.LogError(_myName);
}
}
// 将对象写进二进制文件,存储
void WriteTest()
{
DemoClass demo = new DemoClass (100, "RCD");
FileStream fs = new FileStream ("demo.bin", FileMode.OpenOrCreate);
BinaryFormatter bf = new BinaryFormatter ();
bf.Serialize (fs, demo);
fs.Close ();
Debug.LogError ("write done");
}
//读操作
void ReadTest()
{
FileStream fs = new FileStream("demo.bin", FileMode.Open);
BinaryFormatter bf = new BinaryFormatter();
DemoClass demo = bf.Deserialize(fs) as DemoClass;
fs.Close();
demo.Output();
}
unity 添加Json库的办法
实践发现通过NuGet包管理工具添加在unity中是不识别的,虽然vs不报错,但是editor会报错
正确的姿势:
window -> package manager->+号 ->add package from git URL...
com.unity.nuget.newtonsoft-json
unity 单例SingleMonbehavior实现
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace gslb.core.util
{
public class SingletonMonoBehaviour<T> : MonoBehaviour where T : MonoBehaviour
{
private static object _singletonLock = new object();
private static T _instance;
public static T Instance
{
get
{
if (_instance == null)
{
lock (_singletonLock)
{
T[] singletonInstances = FindObjectsOfType(typeof(T)) as T[];
if (singletonInstances.Length > 1)
{
if (Application.isEditor)
Debug.LogError("MonoSingleton<T>.Instance: Only 1 singleton instance can exist in the scene. Null will be returned.");
return null;
}
if (singletonInstances.Length == 0)
{
GameObject singletonInstance = new GameObject();
_instance = singletonInstance.AddComponent<T>();
singletonInstance.name = "(singleton) " + typeof(T).ToString();
}
else
_instance = singletonInstances[0];
}
_instance = FindObjectOfType<T>();
}
return _instance;
}
}
protected virtual void OnEnable()
{
if (Instance != this)
{
Destroy(this);
}
}
}
}
标签:int,void,event,学习,Unity,delegate,相关,序列化,public
From: https://www.cnblogs.com/jobshenlei/p/17635412.html