访问修饰符
虚属性、虚方法
父类中用virtual修饰的属性和方法即为虚属性、虚方法,子类可重写这些属性和方法,重写时加上override关键字修饰
class Car
{
public virtual string Color{ get; set; }
public virtual void Run()
{
Console.WriteLine("abstract car run");
}
}
class Aodi:Car
{
public override string Color { get; set; }
public override void Run()
{
Console.WriteLine("aodi run");
}
}
隐藏方法
当子类和父类有签名一样的方法时,子类需要在方法上添加修饰符new,从而隐藏父类的方法。
class Car
{
public void OpenDoor()
{
Console.WriteLine("abstract car opendoor");
}
}
class Aodi:Car
{
public new void OpenDoor()
{
Console.WriteLine("aodi opendoor");
}
}
泛型
C#的泛型是真正的泛型,不会被擦除,编译后依然存在,比如List<string>和List<int>编译后是两种不同的类型。
关于泛型类型的约束
约束 | 描述 |
---|---|
where T:struct | 对于结构的约束,类型T必须为值类型 |
where T:class | 类约束 指定类型T必须是引用类型 |
where T:IFly | 指定类型T必须实现接口IFly |
where T:Car | 指定类型T必须继承基类Car |
where T:new() | 构造函数约束,指定类型T必须有一个默认构造函数 |
where T1:T2 | 裸类型约束 指定类型T1派生自类型T2 |
注意:关于构造函数约束,只能为默认构造函数定义约束,不能为其他构造函数定义约束。
泛型类的静态成员
泛型类的静态成员只能在一个类的实例中共享,下面是两个类型的两份静态成员code。
public class Demo<T>
{
public static string code;
}
[TestClass]
public class V
{
[TestMethod]
public void TestVar()
{
Demo<string>.code = "qq";
Demo<int>.code = "pp";
Console.WriteLine(Demo<string>.code);
Console.WriteLine(Demo<int>.code);
}
}
泛型的抗变和协变
协变 ,参数:父类的引用 一可以传子类的对象
抗变,返回:返回父类,不能用子类的引用接受
如果泛型类型用out修饰,那么泛型接口就是协变的,意味着返回类型只能是T。
public interface IMoveable<out T>
{
T GetObject();
}
如果泛型类型用in修饰,那么泛型接口就是抗变的,接口只能把泛型类型T用作方法参数。‘
public interface IMoveable1<in T>
{
void move(T t);
}
’方法的参数是协变的,方法的返回值是抗变的。
参数类型可以传入子类,返回值类型可以返回父类。
可空类型
//Nullable<T>类型 T派生于struct,也就是值类型
//基本类型和struct都有对应的可空类型
int? money;
//常用
bool p = a.HasValue;
int q = a.Value;
int m = a.GetValueOrDefault();
迭代器
包含yield语句的为迭代块,迭代块必须返回IEnumerator或IEnumerable接口或,它们的泛型版本,迭代块可以包含多个yield return或yield break,但不能包含return。
yield return 返回集合的一个元素 并移动到下个元素,yield break可停止迭代。
foreach语句中默认调用GetEnumerator()方法
using System.Collections.Generic;
[TestClass]
public class IEnumerateTest
{
[TestMethod]
public void testEnumable()
{
MyIEnumable m = new MyIEnumable();
foreach (string i in m)
{
Console.WriteLine(i);
}
}
}
class MyIEnumable
{
private string[] vs={"aa","ss","bb"};
public IEnumerator<string> GetEnumerator()
{
for(int i=0;i<vs.Length;i++)
{
yield return vs[i];
}
}
}
运算符
溢出检测
byte b = 255;
checked
{
b++;
}
Console.WriteLine(b.ToString());
int c = 0;
int s = checked(c);
运算符重载
所有运算符重载都用public和static修饰。
注意:在重载 == 和 !=时,还要重写Equals()和 GetHashCode()方法
public class Water
{
private int capacity;
public Water(int capacity)
{
this.capacity = capacity;
}
public int getCapacity()
{
return this.capacity;
}
public static Water operator +(Water w1,Water w2)
{
return new Water(w1.getCapacity() + w2.getCapacity());
}
}
可重载的运算符
隐式类型转换和显示类型转换
和运算符重载有些类似,隐式类型转换用implicit关键字,显示类型转换用explicit关键字。
public class Water
{
private int capacity;
public Water(int capacity)
{
this.capacity = capacity;
}
public int getCapacity()
{
return this.capacity;
}
public static Water operator +(Water w1,Water w2)
{
return new Water(w1.getCapacity() + w2.getCapacity());
}
public static implicit operator int(Water w)
{
return w.getCapacity();
}
public static explicit operator Water(int c)
{
return new Water(c);
}
public void Test()
{
Water w = (Water)0;
int c = w;
}
}
元组
最后一个参数也是元组类型,所以可以包含任意多个项
public class Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>