---恢复内容开始---
编程笔记
override与new实现的版本控制
// versioning.cs // CS0114 expected public class MyBase { public virtual string Meth1() { return "MyBase-Meth1"; } public virtual string Meth2() { return "MyBase-Meth2"; } public virtual string Meth3() { return "MyBase-Meth3"; } } class MyDerived : MyBase { // Overrides the virtual method Meth1 using the override keyword: public override string Meth1() { return "MyDerived-Meth1"; } // Explicitly hide the virtual method Meth2 using the new // keyword: public new string Meth2() { return "MyDerived-Meth2"; } // Because no keyword is specified in the following declaration // a warning will be issued to alert the programmer that // the method hides the inherited member MyBase.Meth3(): public string Meth3() { return "MyDerived-Meth3"; } public static void Main() { MyDerived mD = new MyDerived(); MyBase mB = (MyBase) mD; System.Console.WriteLine(mB.Meth1()); System.Console.WriteLine(mB.Meth2()); System.Console.WriteLine(mB.Meth3()); } }
问题:将借口的类型作为返回对象是什么意思。。。
问题在下一个章节的解答中。
就是迭代器的实现,用来和foreach来匹配
另外Unity里的协程用到的也是迭代器的方法。
上个示例代码
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; class testClass : MonoBehaviour { void Start() { print("?"); TestEnum _t = new TestEnum(10); foreach (string item in _t) { print(item); } } } class TestEnum : IEnumerable { /// <summary> /// 生成n组n位随机数序列 /// </summary> public TestEnum(int num) { _Id = new string[num]; for(int i = 0; i < num; i++) { _Id[i] = UnityEngine.Random.Range(0, 10000f).ToString(); } } string[] _Id; public IEnumerator GetEnumerator() { return new TestEnumtor(this); } class TestEnumtor : IEnumerator { private TestEnum testEnum; private int index = 0; public TestEnumtor(TestEnum testEnum) { this.testEnum = testEnum; } public object Current { get { return testEnum._Id[index]; } } public bool MoveNext() { if (index < testEnum._Id.Length-1) { index++; return true; } else { return false; } } public void Reset() { index = -1; } } }
关于结构和类:
起码的一点,结构是值类型,类对象是引用类型。
同样的,传参时结构是按值传递,而类是按引用传递。
结构不能定义默认构造函数
使用 New 运算符创建结构对象时,将创建该结构对象,并且调用适当的构造函数。与类不同的是,结构的实例化可以不使用 New 运算符。如果不使用“新建”(new),那么在初始化所有字段之前,字段将保持未赋值状态,且对象不可用。
对于结构,不像类那样存在继承。一个结构不能从另一个结构或类继承,而且不能作为一个类的基。但是,结构从基类对象继承。结构可实现接口,而且实现方式与类实现接口的方式完全相同。以下是结构实现接口的代码片段:
索引器的用法
就是能用索引器的方式来返回类里的属性,具体在VS里找到indexer这个提示符就可以补全出这个结构来了,不做赘述.
但是需要注意一点,这个方法最好是get和set属性都使用。一旦只使用set属性,还不如直接用方法来实现,不要用索引器
类型转换
隐式转换implicit和显式转换explicit,也比较好理解。语法上也是结合了运算符重载。
定义了同类型的显示转换/隐式转换就不需要定义另外一种了。
另外记住要声明为static。
直接上个例子就行了
static public implicit operator int(TestEnum te) { Debug.Log("隐式转换"); return te.length; } static public explicit operator int(TestEnum te) { Debug.Log("显示转换"); return te.length; }
(当然,两个都写在这里是错误的)
隐式转换是非常强力的编程工具,但是也可能带来比较难维护的问题吧感觉。
重载运算符
基本和C++的差不多,但是C#的相对来说灵活一点。比如说,+运算符的第一个参数不一定需要是这个类的对象。不像C++里面那样对于二目运算符里的左操作数对类型有要求。(比如<<这个运算符,重载IO流还需要声明是friend)
上个例
static public TestEnum operator +(int t1,TestEnum t2) { return t1+t2.length; }
(这个功能太强了)
当然,这么写的前提是,我定义了从int到TestEnum的隐式转换
static public implicit operator TestEnum(int i) { return new TestEnum(i); }
(所以说隐式转换功力很强劲啊…………)
委托和事件:
之前在《u3d脚本编程》这本书里了解了一些有关知识,再看一遍MSDN上的也就相当于复习。
摘一些MSDN上的TIPs好了,也不能说现在完全理解吧,慢慢理解还是可以的。先码
委托在以下情况下很有用:
- 调用单个方法。
- 一个类可能希望有方法规范的多个实现。
- 希望允许使用静态方法实现规范。
- 希望类似事件的设计模式。
- 调用方不需要知道或获得在其上定义方法的对象。
- 实现的提供程序希望只对少数选择组件“分发”规范实现。
- 需要方便的组合。
接口在以下情况下很有用:
- 规范定义将调用的一组相关方法。
- 类通常只实现规范一次。
- 接口的调用方希望转换为接口类型或从接口类型转换,以获得其他接口或类。
事件按照.NET的标准来的话,就是最好使用EventHandler,或者它的泛型版本(泛型版本是改变了EventArg的类型,一般是继承了EventArg的类(所以为什么不也做一个Object的泛型安全类型版本呢…………))
下面是一个简单的示例
class testClass : MonoBehaviour { void Start() { DataElement data1 = new DataElement("alex", 15); EventListener eva = new EventListener(data1); data1.Name = "tom"; data1.Age = 13; } } class DataElementMessage : EventArgs { public enum ChangeType { NAME, AGE, BOTH, NONE } ChangeType changeType; internal ChangeType ChangeType1 { get { return changeType; } set { changeType = value; } } public DataElementMessage(ChangeType changetypes) { this.ChangeType1 = changetypes; } } class DataElement { private string name; private int age; public string Name { get { return name; } set { name = value; Onchange(new DataElementMessage(DataElementMessage.ChangeType.NAME)); } } public int Age { get { return age; } set { age = value; Onchange(new DataElementMessage(DataElementMessage.ChangeType.AGE)); } } public event EventHandler<DataElementMessage> change; void Onchange(DataElementMessage e) { if (change != null) { change(this, e); } } public DataElement(string name, int age) { this.Name = name; this.Age = age; Onchange(new DataElementMessage(DataElementMessage.ChangeType.BOTH)); } } class EventListener { DataElement _eventsender; public EventListener(DataElement _e) { this._eventsender = _e; _e.change += ListChange; } public void ListChange(object sender, DataElementMessage message) { DataElement data = sender as DataElement; Debug.Log("changeType:" + message.ChangeType1.ToString() + " Age:" + data.Age + " Name:" + data.Name); } }
(当然这个实例没有写Detach,要写也比较容易把,写这个也就是熟悉一下基本框架。注意与MVC的联合思考就好)
显式实现接口:
怎么显式实现借口VS已经在自动补全里告诉你了。这里的关键是使用。
如果一个接口是显式实现的,like this
interface testInterface { float Floating(); } class FloatInterface : testInterface { float testInterface.Floating() { return 2f; } }
那么使用的时候,就必须用接口对象来实现,like this
FloatInterface I = new FloatInterface(); testInterface i = (testInterface)I; Debug.Log( i.Floating());
如果是非显式实现的,那么用FloatInterface的实例对象也可以进行接口调用,反之则不行。
那么这个东西有什么用呢?官方例子里大概意思这么写了一个例子,我也简化随便写了下
interface DoubleInterFace { float Floating(); } interface TrippleInterFace { float Floating(); } class FloatInterface : DoubleInterFace, TrippleInterFace { float DoubleInterFace.Floating() { return 2f; } float TrippleInterFace.Floating() { return 3f; } public float Floating() { return 1f; } } class testClass : MonoBehaviour { void Start() { FloatInterface _1f = new FloatInterface(); TrippleInterFace _3f = _1f; DoubleInterFace _2f = _1f; Debug.Log(_1f.Floating()); Debug.Log(_2f.Floating()); Debug.Log(_3f.Floating()); } }
输出当然是1 2 3
编程笔记