C#中泛型的用法

本文介绍了C#中泛型的使用,包括声明泛型类、创建构造类型和实例,以及泛型在代码复用和维护上的优势。通过示例展示了如何创建和使用泛型类,并探讨了泛型与非泛型栈的区别。此外,还讨论了类型参数的约束,确保泛型类可以使用特定的方法。文章最后强调了泛型在提高代码效率和可维护性方面的价值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

上一篇文章简单介绍了泛型,接下来一起看看泛型在C#中具体该如何用。

具体泛型的使用有如下步骤:

声明泛型类、创建构造类型、创建变量和实例。其实和类的使用一样,只是泛型在初始时,是不指定某类型的,而在使用过程中,确定具体类型。

泛型的用法

声明泛型类

        class Ahui<T,T2> 
        {
            public T Age;
            public T2 Name;
        }

创建构造类型

其实就是声明完泛型类,在使用时,需要告诉编译器能使用那些真实类型来替代占位符(类型参数)。编译器获取真实类型并创建构造类型 。

   Ahui<int, string>
  • 泛型类声明上的类型参数用做类型的占位符。
  • 在创建构造类型时提供的真实类型是类型实参。

创建变量和实例

     Ahui<int, String> ahui2 = new Ahui<int, string>();

可以从同一个泛型类型构建出很多不同的类类型。每一个都有独立的类类型。

     Ahui<int, String> ahui2 = new Ahui<int, string>();
     Ahui<int, int> ahui3 = new Ahui<int, int>();

泛型的应用

        static void Main(string[] args)
        {                       
            Ahui<int, String> ahui2 = new Ahui<int, string>();
            ahui2.Age = 28;
            ahui2.Name = "Andy阿辉";

            Console.WriteLine("输出");
            Console.WriteLine("年龄:"+ahui2.Age);
            Console.WriteLine("姓名:" + ahui2.Name);

            Console.ReadKey();
        }

输出

泛型和非泛型栈的区别

非泛型(常规类型)

  • 源代码更大,需要为每一种类型编写一个新的实现
  • 无论每一个版本的栈是否会被使用,都会在编译的版本中出现
  • 易于书写
  • 更容易出现问题,后期的修改需要对应用到每一个可用的类型上

泛型

  • 源代码更小,只需要一个实现
  • 可执行文件中只会出现有构造类型的类型
  • 比较难写,更加抽象
  • 易于维护,只需要修改一个地方

类型参数的约束

泛型类由于定义时使用占位符来声明,所以不能有一些其它类型都有的共有方法,目前所有的C#对象最终都从Object类继承,它们都包括ToString()、Equals()以及GetType()。那么要让泛型类也拥有这些方法,就必须使用其泛型类的约束。

符合约束的类型参数叫做未绑定的类型参数,要让泛型变得更有用,需要提供额外的信息让编译器知道参数可以接受哪些类型。这些额外的信息叫做约束。

只有符合约束的类型才能替代给定的类型参数,来产生构造类型。

约束使用where字句列出

  • 每一个有约束的类型参数有自己的where字句
  • 如果形参有多个约束,它们在where字句中使用逗号分隔
        class Ahui<T,T2>  where T:IBaseInfo where T2: IComparable         
        {
            public T Age;
            public T2 Name;
        }

寄语

人生短暂,我不想去追求自己看不见的,我只想抓住我能看得见的。

原创不易,给个关注。

我是阿辉,感谢您的阅读,如果对你有帮助,麻烦点赞、转发 谢谢。

### C# 方法的使用示例及详解 #### 什么是方法? 在 C# 中,方法允许开发者定义一种可以操作多种数据类的函数。通过指定类参数 `T` 或其他自定义名称,可以在不改变逻辑的情况下处理不同类的输入和输出。这种方法提高了代码的重用性和灵活性。 以下是关于如何声明、调用以及应用方法的具体说明: --- #### 声明方法 方法可以通过在其返回值前加上 `<T>` 来表示支持。例如: ```csharp public static T GetT<T>(T a) { return a; } ``` 上述代码中,`GetT` 是一个静态方法,它接受任意类的单个参数并将其原样返回[^1]。 --- #### 调用方法 当调用方法时,编译器会尝试推断实际使用的类。如果无法自动推断,则需显式提供类参数。下面是一些具体的例子: ##### 自动类推断 ```csharp int resultInt = Helper.GetT(42); // 编译器推测 T 为 int 类 string resultString = Helper.GetT("Hello"); // 编译器推测 T 为 string 类 ``` ##### 显式指定类 ```csharp double resultDouble = Helper.GetT<double>(3.14); bool resultBool = Helper.GetT<bool>(true); ``` 在这里,即使传入的是整数常量 `3.14` 和布尔字面量 `true`,我们仍然强制指定了目标类作为双精度浮点数 (`double`) 和布尔值 (`bool`)。 --- #### 添加约束条件 (Constraints) 为了增强安全性或者实现特定功能,可能需要对中的类施加某些限制。这称为 **类约束**。常见的几种约束包括但不限于以下几项: - **结构体约束**: 只能传递值类。 - **类约束**: 需要是一个引用类。 - **构造函数约束**: 表明该类必须具有无参公共构造函数。 - **基类/接口约束**: 指定某类应继承某个具体类或实现某一接口。 举个例子来说,如果我们希望我们的只适用于实现了 `IComparable` 接口的对象,那么我们可以这样写: ```csharp public static void PrintMinValue<T>(List<T> list) where T : IComparable { if (list.Count == 0){ Console.WriteLine("The list is empty."); return ; } T minValue = list[0]; foreach(T item in list){ if(item.CompareTo(minValue)<0){ minValue=item; } } Console.WriteLine($"Minimum value: {minValue}"); } ``` 此版本的方法仅限于那些能够比较大小的数据类(即实现了 `IComparable` 的类),从而避免潜在错误发生。 --- #### 实际应用场景 假设我们需要创建一个通用交换两个变量值得工具方法,它可以用于任何基本数据类甚至复杂对象之间互换位置而无需担心兼容性问题。利用前面学到的知识很容易做到这一点: ```csharp public class Utility{ public static void Swap<T>(ref T lhs, ref T rhs){ T temp=lhs; lhs=rhs; rhs=temp; } } // Usage Example: Utility.Swap<int>(ref numA ,ref numB ); Utility.Swap<string>(ref strX ,ref strY ); ``` 以上展示了如何构建灵活且强大的算法组件来满足各种需求场景下的高效开发工作流程。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Andy阿辉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值