在C#中,泛型(Generics)是一种强大的特性,它允许你编写具有通用性的类、接口和方法,以便在编译时指定具体的数据类型。泛型的引入提高了代码的重用性、类型安全性和性能。

泛型种类详解

  1. 泛型类(Generic Class):
    泛型类允许你创建具有通用性的类,其中的字段、属性、方法等可以使用泛型类型参数。

代码示例:

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();

  1. 泛型方法(Generic Method):
    泛型方法允许你在方法中使用泛型类型参数,使方法具有通用性。

代码示例:

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);

  1. 泛型接口(Generic Interface):
    泛型接口允许你创建具有通用性的接口,其中的方法可以使用泛型类型参数。

代码示例:

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;
    }
}

  1. 泛型委托(Generic Delegate):
    泛型委托允许你定义具有通用性的委托,以便在运行时动态指定方法的参数和返回类型。

代码示例:

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");

  1. 泛型约束(Generic Constraint):
    泛型约束允许你限制泛型类型参数的类型,以满足特定的条件。

代码示例:

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必须实现某个接口)等。