C#总结之泛型

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);
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值