C#泛型
接着上一篇《C#总结之集合,比较,转换》,来继续总结C#的基础语法,这篇主要汇总泛型相关的语法及使用方法,包括可空类型,泛型列表,泛型字典集合,自定义泛型,约束类型,泛型接口,泛型方法,泛型委托,协变和逆变等。
1. 可空类型
public class Teacher
{
public string Name;
public List<Course> Courses;
}
public class Course
{
public string Name;
}
// ?操作符的原型
System.Nullable<int> nullableInt;
// 运算符和可空类型
int? op1 = 3;
//int result = (int)op1 * 2;
//int result1 = op1.value * 2;
int? result2 = op1 * 2;
// ?? 运算符
int? op2 = null;
int result3 = op2 * 2 ?? 5;
WriteLine($"result3={result3}");
// ?. 运算符
Teacher teacher = new Teacher();
int? count = teacher.Courses?.Count() ?? 0;
示例:矢量相加相减运算
// 矢量
public class Vector
{
// 半径
public double? R = null;
// 角度
public double? Theta = null;
// 弧度值
public double? ThetaRadians
{
get {
return (Theta * Math.PI / 180.0);
}
}
public Vector(double? r, double? theta)
{
if (r < 0)
{
r = -r;
theta += 180;
}
theta = theta % 360;
R = r;
Theta = theta;
}
// 矢量相加
public static Vector operator +(Vector op1,Vector op2)
{
try
{
double newX = op1.R.Value * Sin(op1.ThetaRadians.Value) +
op2.R.Value * Sin(op2.ThetaRadians.Value);
double newY = op1.R.Value * Cos(op1.ThetaRadians.Value) +
op2.R.Value * Cos(op2.ThetaRadians.Value);
double newR = Sqrt(newX * newX + newY * newY);
double newTheta = Atan2(newX, newY) * 180.0 / PI;
return new Vector(newR, newTheta);
}
catch
{
return new Vector(null, null);
}
}
public static Vector operator -(Vector op1) => new Vector(-op1.R, op1.Theta);
public static Vector operator -(Vector op1, Vector op2) => op1 + (-op2);
public override string ToString()
{
string rString = R.HasValue ? R.ToString() : "null";
string thetaString = Theta.HasValue ? Theta.ToString() : "null";
return string.Format($"({rString} {thetaString})");
}
}
// 使用
static void Main(string[] args)
{
Vector v1 = GetVector("v1");
Vector v2 = GetVector("v2");
WriteLine($"{v1}+{v2}={v1 + v2}");
WriteLine($"{v1}-{v2}={v1 - v2}");
ReadKey();
}
static Vector GetVector(string name)
{
WriteLine($"Input {name} magnitude:");
double? r = GetNullableDouble();
WriteLine($"Input {name} angle (in degrees):");
double? theta = GetNullableDouble();
return new Vector(r, theta);
}
static double? GetNullableDouble()
{
double? result;
string userInput = ReadLine();
try
{
result = double.Parse(userInput);
}
catch
{
result = null;
}
return result;
}
2. 泛型列表
类型 | 说明 |
---|---|
List<T> | T类型对象的集合 |
Dictionary<T> | 与K类型的键值相关的V类型的项的集合 |
其中有两个泛型委托可以用于排序和搜索。
- Comparison<T>:这个委托类型用于排序方法,其返回类型和参数如下:int method(T objectA,T objectB)
- Predicate<T>:这个委托类型用于搜索方法,其返回类型和参数如下:bool method(T targetObject)
// List<T>泛型集合的搜索与排序
public class Vectors:List<Vector>
{
public Vectors()
{
}
public Vectors(IEnumerable<Vector> initialItems)
{
foreach(Vector vector in initialItems)
{
Add(vector);
}
}
public string Sum()
{
StringBuilder sb = new StringBuilder();
Vector currentPoint = new Vector(0.0, 0.0);
sb.Append("origin");
foreach(Vector vector in this)
{
sb.AppendFormat($"+{vector}");
currentPoint += vector;
}
sb.AppendFormat($"={currentPoint}");
return sb.ToString();
}
}
public static class VectorDelegates
{
public static int Compare(Vector x,Vector y)
{
if (x.R > y.R)
{
return 1;
}else if(x.R < y.R)
{
return -1;
}
return 0;
}
public static bool TopRightQuadrant(Vector target)
{
if(target.Theta>=0.0 && target.Theta <= 90.0)
{
return true;
}
else
{
return false;
}
}
}
// 使用
Vectors routes = new Vectors();
routes.Add(new Vector(2.0, 90.0));
routes.Add(new Vector(1.0, 180.0));
routes.Add(new Vector(0.5, 45.0));
routes.Add(new Vector(2.5, 315.0));
WriteLine(routes.Sum());
WriteLine();
Comparison<Vector> sorter = new Comparison<Vector>(VectorDelegates.Compare);
routes.Sort(sorter);
WriteLine(routes.Sum());
WriteLine();
Predicate<Vector> searcher = new Predicate<Vector>(VectorDelegates.TopRightQuadrant);
Vectors topRightQuadrantRoute = new Vectors(routes.FindAll(searcher));
WriteLine(topRightQuadrantRoute.Sum());
3. 泛型字典集合
Dictionary<K,V>类型可以定义键值对的集合
Dictionary<string, int> things = new Dictionary<string, int>();
things.Add("Green Things", 29);
things.Add("Blue Things", 45);
things.Add("Yellow Things", 34);
things.Add("Red Things", 52);
things.Add("Brown Things", 27);
Dictionary<string, int> things2 = new Dictionary<string, int>()
{
{"Green Things",29 },
{ "Blue Things", 45 }
};
// 忽略定义键的大小写
Dictionary<string, int> things3 = new Dictionary<string, int>(StringComparer.CurrentCultureIgnoreCase);
// 使用索引初始化器
var things4 = new Dictionary<string, int>
{
["Green"] = 29,
["Blue"] = 33,
};
Dictionary<string, int> SomeThings() => new Dictionary<string, int>
{
["Green"] = 29,
["Blue"] = 33,
};
foreach (string key in things.Keys)
{
WriteLine(key);
}
foreach(int value in things.Values)
{
WriteLine(value);
}
foreach(KeyValuePair<string,int> thing in things)
{
WriteLine($"{thing.Key}={thing.Value}");
}
4. 自定义泛型类型
泛型类可在其定义中包含任意多个类型参数,参数之间用逗号分隔。default关键字用于值类型和引用类型默认值的自适应。
4.1 定义泛型类
class MyGenericClass<T1,T2,T3>
{
private T1 innerT1Object;
public MyGenericClass()
{
innerT1Object=default(T1);
}
}
4.2 约束类型
约束类型可以限制用于实例化泛型类的类型。
class MyGenericClass where T: constraint {…}
class MyGenericClass where T: constraint1,constraint2 {…}
class MyGenericClass<T1,T2> where T1: constraint1 where T2:constraint2 {…}
class MyGenericClass<T1,T2>:MyBaseClass,IMyInterface where T1: constraint1 where T2:constraint2 {…}
class MyGenericClass<T1,T2> where T2:T1 {…} //裸类型约束,T2必须与T1类型相同,或者继承自T1。
举例说明,创建一个泛型类Farm,,且约束为Animal,或者继承自Animal。
// 抽象动物基类
public abstract class Animal
{
protected string name;
public string Name
{
get { return name; }
set { name = value; }
}
public Animal() => name = "The animal with no name";
public Animal(string newName) => name = newName;
public void Feed() => WriteLine($"{name} has been fed.");
public abstract void MakeANoise();
}
// 奶牛子类
public class Cow : Animal
{
public Cow(string newName) : base(newName) { }
public void Milk() => WriteLine($"{name} has been milked.");
public override void MakeANoise()
{
WriteLine($"{name} says 'moo!';");
}
}
// 母鸡子类
public class Chicken : Animal
{
public Chicken(string newName) : base(newName) { }
public void LayEgg() => WriteLine($"{name} has laid an egg.");
public override void MakeANoise()
{
WriteLine($"{name} says 'cluck!';");
}
}
public class SuperCow : Cow
{
public void Fly()
{
WriteLine($"{name} is flying!");
}
public SuperCow(string newName) : base(newName)
{}
public override void MakeANoise()
{
WriteLine($"{name} says 'super moo!';");
}
}
public class Farm<T> :IEnumerable<T> where T:Animal
{
private List<T> animals = new List<T>();
public List<T> Animals
{
get { return animals; }
}
public IEnumerator<T> GetEnumerator() => animals.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => animals.GetEnumerator();
public void MakeNoises()
{
foreach(T animal in animals)
{
animal.MakeANoise();
}
}
public void FeedTheAnimals()
{
foreach(T animal in animals)
{
animal.Feed();
}
}
public Farm<Cow> GetCows()
{
Farm<Cow> cowFarm = new Farm<Cow>();
foreach(T animal in animals)
{
if(animal is Cow)
{
cowFarm.Animals.Add(animal as Cow);
}
}
return cowFarm;
}
// 泛型方法
public Farm<U> GetSpecies<U>() where U : T
{
Farm<U> speciesFarm = new Farm<U>();
foreach(T animal in animals)
{
if(animal is U)
{
speciesFarm.Animals.Add(animal as U);
}
}
return speciesFarm;
}
// 重载隐式转换运算符
public static implicit operator List<Animal>(Farm<T> farm)
{
List<Animal> result = new List<Animal>();
foreach(T animal in farm)
{
result.Add(animal);
}
return result;
}
// 重载运算符
public static Farm<T> operator +(Farm<T> farm1,Farm<T> farm2)
{
Farm<T> result = new Farm<T>();
foreach(T animal in farm1)
{
result.Animals.Add(animal);
}
foreach(T animal in farm2)
{
if (!result.Animals.Contains(animal))
{
result.Animals.Add(animal);
}
}
return result;
}
}
static void Main(string[] args)
{
Farm<Animal> farm = new Farm<Animal>();
farm.Animals.Add(new Cow("cow1"));
farm.Animals.Add(new Chicken("chicken1"));
farm.Animals.Add(new Chicken("chicken2"));
farm.Animals.Add(new SuperCow("cow2"));
farm.MakeNoises();
Farm<Cow> dairyFarm = farm.GetCows();
// 调用泛型方法
Farm<Cow> dairyFarm = farm.GetSpecies<Cow>();
dairyFarm.FeedTheAnimals();
foreach(Cow cow in dairyFarm)
{
if (cow is SuperCow)
{
(cow as SuperCow).Fly();
}
}
List<Animal> animals = farm;
foreach(var animal in animals)
{
WriteLine($"animal={animal.Name}");
}
ReadKey();
}
4.3 定义泛型接口
interface MyFarmingInterface<T> where T: Animal
{
bool AttemptToBreed(T animal1,T animal2);
T OldestInHerd {get;}
}
4.4 泛型方法
public T GetDefault<T>()=>default(T);
// 泛型类和泛型方法中的标识必须不同!
public class Defaulter<T1>
{
public T2 GetDefault<T2>() where T2:T1
{
return default(T2);
}
}
4.5 泛型委托
public delegate T1 MyDelegate<T1,T2>(T2 op1, T2 op2) where T1:T2;
4.6 逆变与协变
可变性是以一种类型安全的方式,将一个对象当做另一个对象来使用。如果不能将一个类型替换为另一个类型,那么这个类型就称之为:不变量。协变和逆变是两个相互对立的概念:
- 如果某个返回的类型可以由其派生类型替换,那么这个类型就是支持协变的
- 如果某个参数类型可以由其基类替换,那么这个类型就是支持逆变的。
在C# 4.0之前的泛型都是不支持协变和逆变的。
static void Main(string[] args)
{
List<Cow> cows = new List<Cow>();
cows.Add(new Cow("cow1"));
cows.Add(new SuperCow("super cow"));
cows.Add(new Cow("mike cow"));
cows.Add(new Cow("jake cow"));
// 协变,用于返回的类型,子类强转成父类
IEnumerable<Animal> animals = cows;
ListAnimals(animals);
// 逆变,用于方法参数,理解:父类强转成子类
IComparer<Animal> iAnimal = new AnimalNameLengthComparer();
IComparer<Cow> iCow = iAnimal;
cows.Sort(iCow);
WriteLine();
ListAnimals(cows);
ReadKey();
}
// 协变
static void ListAnimals(IEnumerable<Animal> animals)
{
foreach(Animal animal in animals)
{
WriteLine(animal.Name.ToString());
}
}
// 逆变
public class AnimalNameLengthComparer : IComparer<Animal>
{
public int Compare(Animal x, Animal y) => x.Name.Length.CompareTo(y.Name.Length);
}