委托:比较什么时候用委托好
下课案例:不用下课铃
1、ClassManager需要拿到所有教室的引用,课堂管理者应该只负责计时并告知每间教室
2、每间教室应该是由当班老师负责是否需要下课,而课堂管理者应该负责告知时间到,并不应该强制执行下课方法
3、每间教室的类可能不是同一个程序员写的,下课方法也不一定一样,比如有100间教室,每间教室下课方法都不一样
使用下课铃(广播)的好处:
1、ClassManager并不需要知道每间教室的地址
2、只负责告知每间教室时间到了,并没有强制要求下课,具体下不下课,是由ClassManager类里面的方法决定的
3、谁想要接收下课的广播就接收,发送者并不需要知道谁在接收,接收到之后具体要干什么,自己说了算
public delegate 返回值类型 类型名 (参数列表)
public 类型名 委托变量名;//相当于一个函数的大容器
发送广播的方式:
委托变量名();//函数指针
监听广播的方式:
委托变量名 += 我收到广播之后的行为
单例:
二十三种设计模式中的一种
整个游戏进程中或者过程中,只有一个实例化出来的类对象,这种设计模式叫单一实例化或单例。
实例化:把类变成实体对象
只需要实例化一次,也只有一个类对象:玩家1个,玩家管理器1个,
静态类,外部可以直接使用类名来使用
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerManager : MonoBehaviour { //PlayerManager只有一个实例化 private static PlayerManager _instance;//用private把-instance隐藏掉 public static PlayerManager GetIntance//声明一个GetIntance属性,保护-instance,只有get { get { if (_instance == null) { _instance = new PlayerManager();//GetIntance 保证每次使用,都是第一次new出来的对象-instance } return _instance; } } private PlayerManager()//隐藏构造函数,防止使用new PlayerManager,只能使用GetIntance { } }
但是多线程,存在安全问题,会同时执行GetIntance,生成两个-instance,需要线程锁
单例第二种写法
下次访问类名.对象,直接把自己拿过去
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace RedisTest.Test { [Serializable] public class TestClass { public string Name = ""; public TestClass(string n) { Name = n; } public override bool Equals(object obj) { TestClass other = obj as TestClass; if (other == null) return false; if (!base.GetType().Equals(obj.GetType())) return false; return (this.Name.Equals(other.Name)); } public override int GetHashCode() { return Name.GetHashCode(); } public static explicit operator TestClass(string jsonString) { return Newtonsoft.Json.JsonConvert.DeserializeObject<TestClass>(jsonString); } public override string ToString() { return Newtonsoft.Json.JsonConvert.SerializeObject(this); } } }
教室1
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ClassRoom_1 : MonoBehaviour { //public ClassManager manager; // Use this for initialization void Start () { //manager.classOver += ClassOver; //ClassManager._instance.classOver += ClassOver; } // Update is called once per frame void Update () { } public void ClassOver() { Debug.Log("教室1下课了"); //manager.classOver += ClassOver; //ClassManager._instance.classOver -= ClassOver; } }
教室2
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ClassRoom_2 : MonoBehaviour { // Use this for initialization void Start () { } // Update is called once per frame void Update () { } public void ClassOver() { Debug.Log("教室2下课了"); } }
考试复习
C#基础: 1、下列有关基本类的大小不正确的是 D A、int类型是4个字节 B、bool类型是1个字节 C、long类型是8个字节 D、char类型是一个字节 //char类型占两个字节 2、关于定义数组定义不正确的是 C A、int[] numbers={1,2,3,4,5,6}; B、int[] numbers=new int[6]; C、int[][] numbers=new int[2][3];//定义二维数组的正确方法:int[,] a =new int [3,5]; D、var a=new[]{1,2,3,4,5,6}; 3、有关数组说法不正确的是 A A、数组的内存是分配在栈中//堆 B、数组的索引从零开始的 C、数组是一种数据结构,它包含若干相同的类型的变量 D、数组可以是一维、多维、交错的 4、有关结构体说法不正确的是 D A、在结构体声明中,除非字段被声明为const或static,否则无法初始化 B、结构体不能声明默认的构造函数(没有参数的构造函数)或析构函数 C、结构体不能从类或其他结构体继承 D、结构体是引用类型的//结构体是值类型,类是引用类型 5、有关结构体和类的说法不正确的是 B A、结构是值类型的,而类是引用类型的 B、结构体不可以声明构造函数//不能声明无参构造,可以声明有参构造 C、结构体直接继承System.ValueType类型 D、结构体可以继承接口//结构体不能继承类,可以继承接口 6、关于静态类说法不正确的是 C A、声明静态类,该类不能使用new关键字创建实例 B、静态仅包含静态成员//const常量 C、静态类不能包含常量成员 D、静态类是密封的//不能被继承,隐含密封 7、有关委托的说法不正确的是 C A、一旦为委托分配了方法,委托与该方法具有完全相同的行为 B、委托是一种引用方法的类型 C、委托可以链接在一起,方法不必与委托签名完全匹配//必须和委托签名匹配 8、delegate void Del(int x); C void DoWork(int k); 下列关于委托订阅不正确的是 A、Del d=DoWork; B、Del d=new Del(DoWork); C、Del d+=DoWork//还未创建,不可订阅 D、Del d=delegate(int x){DoWork(x);}; //看匿名委托和委托的签名是否一致 9、有关静态构造函数说法不正确的是 C A、静态构造函数既没有访问修饰符,也没有参数 B、在创建第一个实例前或引用任何静态成员之前,将自动调用静态构造函数来初始化。//初始化静态成员 C、在程序中,用户可以控制何时执行静态构造函数//间接执行:调用静态成员,实例化对象 D、无法直接调用静态构造函数 10、有关继承需要用的关键字说法正确的是 ACD A、virtual用于修饰方法、属性、索引器或事件,并使它们可以在派生类中被重写。 B、virtual可以和static、abstract、private、override修饰符一起使用。//都不可以 C、override关键字提供从基类继承的成员的新的实现,重写的基类方法必须是virtual、abstract、或override关键字修饰的。 D、Sealed用于修饰类时,将会阻止其他类从该类派生//修饰方法,禁止被重写 11、以下c#代码: using System.Threading; class App { public static void Main() { Timer timer = new Timer(new TimerCallback(CheckStatus), null, 0, 2000); Console.Read(); } static void CheckSatus(Object state) { Console.WriteLine("正在进行检查..."); } } 在使用代码创建定时器对象的时候,同时指定了定时器的事件,运行时将每隔两秒打印一行“正在运行检查...”,因此,TimerCallback是一个( ) A A.委托//目前只有委托可以把方法当做参数传递 B.结构 C.函数 D.类名 12、 阅读以下的C#代码: public class TEApp { public static void ThrowException() { throw new Exception(); } public static void Main() { try { Console.WriteLine("try"); ThrowException(); } catch (Exception e) { Console.WriteLine("catch"); } finally { Console.WriteLine("finally"); } } } 请问代码运行结果是( )。(选择一项) A A.try catch finally B.try C.try catch D.try finally 抛异常的用法: try:包含异常的语句 try不能单独使用,要搭配catch和finally使用 catch:捕获异常,可以填参数 catch(Exception e){},(Exception是所有异常的基类) finally:最后都会执行,作为替补收尾工作, 无论如何都会执行,即使前面有return 结果:输出“捕获到了异常”,而“11111”不会输出 13、在C#中,一个类( ).(选择一项) B A.可以继承多个类//类的单根性,只能有一个父类 B.可以实现多个接口 C.在一个程序中只能有一个子类 D.只能实现一个接口 14、程序运行过程中发生的错误,叫作( ).(选择一项) C A.版本 B.断点 C.异常 D.属性 15、针对下面的C#代码: using System; delegate void D(int i); class P { public static void Main() { V(new D(R)); } public static void R(int t) { V(21); } public static void V(int i) { Console.WriteLine(i.ToString()); Console.ReadLine(); } } 以下说法正确的是( )(选择一项) B A.代码中存在错误,delegate voidD(int i);不能定义在名称空间或者类之外//可以定义在类之外 B.代码中存在错误,代码行V(new D(R));使用委托错误//V方法需要整形参数,却传了委托 C.程序正常运行,输出为0 D.程序正常运行,输出为21 16、被volatile关键字修饰字段的作用是( ) B A、提供给子类使用,不提供给其他类使用 B、禁止对字段的访问施加优化 C、表示只读字段,只能赋值一次 D、只能在本程序集中使用 变量修饰符,在多线程中使用,对于值类型的变量,禁止多次拷贝,只能有一份,避免数据不同步(禁止将变量的值存在cache缓存里,只能从内存里拿) 17、在C#中,可以通过装箱和拆箱实现值类型与引用类型之间相互转换,在下列代码中,有( )处实现了拆箱。(选择一项) B 装箱:把值类型的数据放到引用类型的变量里 拆箱:把引用类型的数据放到值类型的变量里(强转) 装箱和拆箱的条件:需要有继承关系 string a = “123”; //不是装箱,String和int没有继承关系 object o = string; //不是装箱,String是引用类型 int age = 5; object o= age; //装箱:子类对象存放在父类里,里氏转换 o=10; //装箱 age=(int)o; //拆箱 object oAge =age; //装箱 A.0 B.1 C.2 D.3 18、在C#中,接口与抽象基类的区别在于( )。(选择一项) A A.抽象基类可以包含非抽象方法,而接口只能包含抽象方法//抽象类什么都可以放,接口:属性(get和set方法),方法,索引器(属性),事件(委托-方法),本质都是方法 B.抽象基类可以被实例化,而接口不能被实例化 C.抽象基类不能被实例化,而接口可以被实例化//抽象类不可以被实例化,而接口不能被实例化 D.抽象基类能够被继承,而接口不能被继承//接口可以继承 19、下列关于 C# 中索引器理解正确的是 ( ) C A、索引器的参数必须是两个或两个以上 //个数任意,但不能无 B、索引器的参数类型必须是整数型 //字符串,枚举 C、索引器没有名字 //this[ in index] D、以上皆非 20、以下关于 ref 和 out 的描述哪些项是正确的? ( 多选 ) ( ) ACD A、使用 ref 参数,传递到 ref 参数的参数必须最先初始化。 B、使用 out 参数,传递到 out 参数的参数必须最先初始化。//可以放在方法内部 C、使用 ref 参数,必须将参数作为 ref 参数显式传递到方法。 D、使用 out 参数,必须将参数作为 out 参数显式传递到方法 算法题 1、一个笼子里面关了鸡和兔子(鸡有2 只脚,兔子有4 只脚,没有例外)。已经知道了笼子里面脚的总数a,问笼子里面至少有多少只动物,至多有多少只动物?请用C#语言实现这个计算过程; 2、有一个数组 “int a[100]” 使用冒泡排序实现数组内的排序(C#语言实现): 3、获得一个int型的数中二进制中的1的个数(C#语言实现) using System; class Program { static void Main(string[] args) { int x = 100; for (int i = 0; i < 32; i++) { Console.WriteLine("位{0} = {1}", i, GetBit(x, i)); } Console.ReadKey(); } // 获取指定位的值 static int GetBit(int x, int bit) { return (x >> bit) & 1; } } 4、输入一个数组,实现一个函数,让所有奇数都在偶数前面(C#语言实现) Unity3D方面 1、Unity3D引擎中最基本的计量单位是什么?米 2、Unity3D中实现运动组件的位置变化的两种方法?(请用C#语言实现) transform.Translate(Vector3.forward); Rigidbody rb = GetComponent<Rigidbody>(); rb.AddForce(Vector3.forward, ForceMode.Force); 3、一个GameObject对象最基本的组件是什么?请描述这个组件的基本功能! 4、请用C#代码实现给一个游戏个体添加上刚体组件,并且需要这个游戏对象可以支持碰撞和穿透效果; Rigidbody rb = gameObject.AddComponent<Rigidbody>(); BoxCollider box = gameObject.AddComponent<BoxCollider>(); 5、如何获取一个对象上的”MyTestScript.cs”脚本?(请用C#语言实现) MyTestScript myScript = gameObject.GetComponent<MyTestScript>(); 6、请用Unity中的四元数绕一个点(20.0f, 30.0f, 0.1f)的X轴顺时针旋转20度。(请用C#语言实现) Void Start() { } voie MyRotateAround(Vector3 pos, Vector3 axis, float angle) { Quaternion q = Quaternion.AngleAxis(angle, axis); Vector3 dir = transfor.position - pos; Vector3 projectV = (Vector3.Dot(axis, dir) / axis.magnitude) * axis.normalized; Vector3 n = dir - projectV; Vector3 newN = q * n; Vector3 newPos = pos + projectV + newN; transform.position = newPos; transform.rotation *= q; } 7、请阐述:如果我们创建了一个游戏对象后后我们需要添加哪些的组件才能使Unity引擎将其渲染出来。(请用C#实现组件的添加代码)