在C#中,泛型是一种强大的特性,它允许你编写可以适用于多种类型的类、方法和数据结构。通过泛型,你可以编写更加灵活和可重用的代码,而不需要对每种数据类型都编写不同的实现。
下面是一个简单的示例,展示了如何创建一个泛型方法:
using System;
public class GenericClass<T>
{
public T GenericMethod(T value)
{
Console.WriteLine("The value is: " + value);
return value;
}
}
class Program
{
static void Main()
{
// 创建一个泛型类实例
GenericClass<int> genericInt = new GenericClass<int>();
int resultInt = genericInt.GenericMethod(10);
GenericClass<string> genericString = new GenericClass<string>();
string resultString = genericString.GenericMethod("Hello");
// 输出结果
Console.WriteLine("Result int: " + resultInt);
Console.WriteLine("Result string: " + resultString);
}
}
泛型约束
在C#中,有多种泛型约束可以用于限制泛型类型参数。以下是常用的泛型约束:
-
where T : class
- 约束类型参数必须是引用类型(类、接口、委托或数组类型),而不能是值类型。
-
where T : struct
- 约束类型参数必须是值类型(如基本数据类型、结构体等),而不能是引用类型。
-
where T : new()
- 约束类型参数必须具有无参数构造函数。
-
where T :
- 约束类型参数必须是指定的基类或其派生类。
-
where T :
- 约束类型参数必须实现指定的接口。
-
where T : U
- 约束类型参数必须派生自指定的类型参数 U。
-
where T : U?
- 约束类型参数必须是可空类型,并且可空类型的基础类型必须满足所指定的约束 U。
这些泛型约束可以单独使用,也可以组合使用,以满足更复杂的约束条件。例如,你可以同时使用多个接口约束类型参数:where T : IComparable, ICloneable。这样就限制了类型参数必须同时实现IComparable
和ICloneable
接口。
泛型协变和逆变
当我们在C#中使用泛型协变和逆变时,通常会在接口或委托中定义泛型类型参数,并使用out
和in
关键字来指示协变和逆变。下面是一个简单的示例来展示泛型协变和逆变的具体代码实现:
// 定义一个简单的动物类
class Animal { }
// 定义一个派生类狗
class Dog : Animal { }
// 定义一个接口,使用泛型协变
interface IAnimal<out T>
{
T GetAnimal();
}
// 实现泛型协变的接口
class AnimalFactory : IAnimal<Dog>
{
public Dog GetAnimal()
{
return new Dog();
}
}
// 定义一个接口,使用泛型逆变
interface IAnimalHandler<in T>
{
void HandleAnimal(T animal);
}
// 实现泛型逆变的接口
class AnimalHandler : IAnimalHandler<Animal>
{
public void HandleAnimal(Animal animal)
{
Console.WriteLine("Handling animal");
}
}
// 在主程序中使用协变和逆变
class Program
{
static void Main()
{
IAnimal<Animal> animal1 = new AnimalFactory();
Animal animal2 = animal1.GetAnimal(); // 协变允许将IAnimal<Dog>赋值给IAnimal<Animal>
IAnimalHandler<Dog> handler1 = new AnimalHandler();
handler1.HandleAnimal(new Dog()); // 逆变允许将IAnimalHandler<Animal>赋值给IAnimalHandler<Dog>
}
}
在上面的示例中,我们定义了一个Animal
类和一个Dog
类作为派生类。然后,我们定义了两个接口IAnimal
和IAnimalHandler
,分别使用了泛型协变和逆变。接着,我们实现了这两个接口,并在主程序中展示了如何使用协变和逆变。