在C#中,泛型(Generics)是一种强大的特性,它允许你编写具有通用性的类、接口和方法,以便在编译时指定具体的数据类型。泛型的引入提高了代码的重用性、类型安全性和性能。
泛型种类详解
代码示例:
public class GenericClass<T>
{
private T data;
public GenericClass(T input)
{
data = input;
}
public T GetData()
{
return data;
}
}
// 使用泛型类
GenericClass<int> intContainer = new GenericClass<int>(42);
int intValue = intContainer.GetData();
GenericClass<string> stringContainer = new GenericClass<string>("Hello, Generics!");
string stringValue = stringContainer.GetData();
代码示例:
public class GenericMethods
{
public T GetMax<T>(T first, T second) where T : IComparable<T>
{
return first.CompareTo(second) > 0 ? first : second;
}
}
// 使用泛型方法
GenericMethods genericMethods = new GenericMethods();
int maxInt = genericMethods.GetMax(10, 20);
double maxDouble = genericMethods.GetMax(3.14, 2.71);
代码示例:
public interface IRepository<T>
{
void Add(T item);
T GetById(int id);
}
public class UserRepository : IRepository<User>
{
public void Add(User user)
{
// 实现添加用户的逻辑
}
public User GetById(int id)
{
// 实现获取用户的逻辑
return null;
}
}
代码示例:
public delegate T MyGenericDelegate<T>(T input);
public class GenericDelegates
{
public int Square(int x)
{
return x * x;
}
public string Reverse(string str)
{
return new string(str.Reverse().ToArray());
}
}
// 使用泛型委托
GenericDelegates genericDelegates = new GenericDelegates();
MyGenericDelegate<int> squareDelegate = genericDelegates.Square;
int squaredResult = squareDelegate(5);
MyGenericDelegate<string> reverseDelegate = genericDelegates.Reverse;
string reversedResult = reverseDelegate("hello");
代码示例:
public class GenericConstraints<T> where T : class, new()
{
public T CreateInstance()
{
return new T();
}
public void ProcessItem(T item)
{
// 处理泛型参数
}
}
// 使用泛型约束
GenericConstraints<MyClass> constrainedObject = new GenericConstraints<MyClass>();
MyClass instance = constrainedObject.CreateInstance();
常见问题:
什么是泛型,为什么我们需要它?
答案:泛型是一种C#中的编程机制,允许我们在编写类、方法、接口时使用通用类型,提高了代码的重用性、类型安全性和性能。通过泛型,我们可以编写更加通用的代码,而不必针对每种数据类型都创建不同的实现。
泛型与非泛型代码的主要区别是什么?
答案:非泛型代码在编写时需要明确指定数据类型,而泛型代码在编写时使用通用类型,可以在编译时指定具体的类型。泛型提供了更灵活、通用的代码结构,使得代码更易于维护和扩展。
什么是泛型类和泛型方法?能否举例说明?
答案:泛型类是具有一个或多个泛型类型参数的类,例如List。泛型方法是在方法中使用泛型类型参数,例如实现一个通用的排序方法。示例见前述回答。
泛型约束是什么?为什么使用泛型约束?
答案:泛型约束是一种限制泛型类型参数的类型的机制。通过使用泛型约束,我们可以确保泛型类型参数满足特定的条件,例如实现了某个接口、具有默认构造函数等。这提高了泛型代码的灵活性和类型安全性。
什么是协变性和逆变性?在泛型中如何应用这两个概念?
答案:协变性和逆变性是指类型在派生或基类型上的变化。在C#中,协变性可以在接口和委托中使用关键字out,逆变性可以在接口和委托中使用关键字in。这允许我们在不破坏类型安全性的前提下进行类型的转换。
协变性(Covariance)示例
// 定义一个协变接口
public interface ICovariant<out T>
{
T GetItem();
}
// 实现协变接口
public class CovariantClass<T> : ICovariant<T>
{
private T item;
public CovariantClass(T value)
{
item = value;
}
public T GetItem()
{
return item;
}
}
// 使用协变接口
ICovariant<Animal> animalCovariant = new CovariantClass<Dog>(new Dog());
Animal myAnimal = animalCovariant.GetItem();
逆变性(Contravariance)示例
// 定义一个逆变接口
public interface IContravariant<in T>
{
void SetItem(T item);
}
// 实现逆变接口
public class ContravariantClass<T> : IContravariant<T>
{
public void SetItem(T item)
{
// 处理传入的项目
}
}
// 使用逆变接口
IContravariant<Dog> dogContravariant = new ContravariantClass<Animal>();
dogContravariant.SetItem(new Dog());
什么是泛型委托?举例说明其用法。
答案:泛型委托是具有泛型类型参数的委托。它允许在运行时指定方法的参数和返回类型。示例见前述回答。
泛型与装箱拆箱有什么关系?如何避免不必要的装箱拆箱操作?
答案:泛型可以避免不必要的装箱拆箱操作,因为它允许在编译时指定具体的数据类型,而不是使用通用的object类型。这提高了性能,并避免了装箱拆箱可能引发的运行时异常。
在泛型中使用的常见约束有哪些?
答案:常见的泛型约束包括where T : class(T必须是引用类型)、where T : struct(T必须是值类型)、where T : new()(T必须有无参数的构造函数)、where T : SomeInterface(T必须实现某个接口)等。