csharp:类:泛型

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
csharp:类:泛型 [2025/09/28 16:37] 张叶安csharp:类:泛型 [2025/11/27 17:25] (当前版本) 张叶安
行 1: 行 1:
-概念+====== C泛型 (Generics) ======
  
-使用在类与方法上、使用占位符T 来代表某种类型,编译期间决定其具体类型+===== 1. 概念 =====
  
-名称后面加 <T代表就是泛类、不一是T <M>  <Myt> ......+泛型主要用于与方法上,使用占位符(通常是 ''T'')来代表某种类型,**在编译期间决其具体类型**。
  
-泛型在实例化时或使用时占位符T会被特化成指定的类型+  * 类名称后面加 ''<T>'' 代表该类就是泛型类。 
 +  * 占位符不一定是 ''T'',也可以是 ''<M>'', ''<Myt>'' 等,但习惯上使用 ''T'' (Type)。 
 +  * 泛型在实例化时或使用时),占位符 ''T'' 会被**特化**成指定的类型
  
-为什么要加<T>  变成泛型+==== 为什么要使用泛型? ====
  
-<T>:是类型占位符表示还没决定具体是什么类型先把这个位置占了+''<T>'' 是类型占位符表示还没决定具体是什么类型先把这个位置占了
  
-如下+**场景举** 
 +当不确定类里面是 ''int[]'' 类型数组,还是 ''string[]'' 类型数组,或者是其他类型的数组时,使用泛型可以避免重复写多个逻辑相同的类。
  
-当不确定类里面 是int[]类数组 或者string[]型数组 疑惑别的数组+===== 2. 泛型类 =====
  
-# 泛型类: +这是一个模拟(Stack)内存空间的泛型类示例。
-``` +
-        class zhan<T> +
-        {   //看做栈内存空间 +
-            private T[] zhan_Cpu = new T[300] ; +
-            //将数据存入栈方法 +
-            public void set(T valu , int index) +
-            { +
-                zhan_Cpu[index] = valu; //数据入栈 +
-            }+
  
-            //将数据取出栈的方法 +<code csharp> 
-            public get(int index) +class zhan<T> 
-            +   
-                return zhan_Cpu[index];//数据取出 +   // 看做栈内存空间 
-            } +   private T[] zhan_Cpu = new T[300];
-        } +
-//使用: +
-        static void Main(string[] args) +
-        {   //对泛型类zhan的特化、特化为int类型的类 +
-            zhan<int> int_data = new zhan<int>(); +
-            // 此时int_data对象 内的数组zhan_Cpu读写都是int类型+
  
-            zhan<string> str_data = new zhan<string>() ; +   // 将数据存入栈的方法 
-            // 此时str_data对象 内的组zhan_Cpu读写都是string类型+   public void set(T valu, int index
 +   { 
 +      zhan_Cpu[index] = valu; // 数据入栈 
 +   }
  
-            zhan<double> doub_data = new zhan<double>() ; +   // 将数据取出栈的方法 
-            // 此时doub_data对象 内的组zhan_Cpu读写都是double类型+   public T get(int index
 +   { 
 +      return zhan_Cpu[index]; // 数据取出 
 +   } 
 +}        
  
-        }+// 使用示例: 
 +class Program  
 +
 +   static void Main(string[] args) 
 +      
 +      // 1. 对泛型类 zhan 的特化、特化为 int 类型的类 
 +      zhan<int> int_data = new zhan<int>(); 
 +      // 此时 int_data 对象内的数组 zhan_Cpu 读写都是 int 类型
  
-```+      // 2. 特化为 string 类型 
 +      zhan<string> str_data = new zhan<string>(); 
 +      // 此时 str_data 对象内的数组 zhan_Cpu 读写都是 string 类型
  
 +      // 3. 特化为 double 类型
 +      zhan<double> doub_data = new zhan<double>();
 +      // 此时 doub_data 对象内的数组 zhan_Cpu 读写都是 double 类型
 +   }
 +}
 +</code>
  
-泛型格式:+===== 3. 泛型方法与 dynamic =====
  
-格式无返回值: +==== 格式无返回值 ====
-``` +
-             void fangfa<T> ( T a  ,  T b) +
-            {+
  
-            +<code csharp> 
-```+void fangfa<T>(T a, T b) 
 +
 +    // 方法体 
 +
 +</code>
  
-格式有返回值: +==== 格式有返回值与 dynamic ====
-``` +
-        public  T fangfa1<T>(T a, T b) +
-        { +
-            return a + b; //报错运算符不能用于两个T类型的操作数 +
-                          //编译器会在编译时会对参数ab校验是否正确、+
  
-            dynamic da = a; //dynamic将类校验推延到行时、 +在泛中直接进行算术算(如 ''a + b'')通常会报错,因编译器不知道 ''T'' 是否支持相加。可以使用 ''dynamic'' 关键字解决。
-            dynamic db = b; //当运行时已经为T类型赋予了int或者double类型 +
-            return da + db; +
-        } +
-```+
  
-dynamic   动态的[当行时根据传过来确定其类型]+<code csharp> 
 +public T fangfa1<T>(T a, T b) 
 +
 +    // return a + b; // 报错:算符不能用于两个 T 类型操作数 
 +    // 原因:编译器会在编译时对参数 a, b 校验,无法确定 T 是否支持 + 运算
  
-daɪˈnæ mɪk+    dynamic da = a; // dynamic 将类型校验推延到运行时 
 +    dynamic db = b;  
 +     
 +    // 当运行时,已经为 T 类型赋予了 int 或者 double 类型,此时可以相加 
 +    return da + db; 
 +
 +</code>
  
-# 多样化泛型+> **dynamic (动态)**
  
-```+  *   发音:/daɪˈnæ mɪk/ 
 +  *   作用:当运行时根据传过来的值确定其类型,跳过编译器的静态检查。 
 + 
 +===== 4. 多样化泛型 ===== 
 + 
 +泛型可以定义多个占位符,用于处理多种不同类型的数据。 
 + 
 +<code csharp>
 class Program class Program
 { {
     static void Main(string[] args)     static void Main(string[] args)
     {        {   
-      reyy<int, string, double> Fanxing = new reyy<int, string, double>(); +        // 实例化时,分别指定 T=int, U=string, F=double 
-      Fanxing.LeiXing_1[1] = 500; +        reyy<int, string, double> Fanxing = new reyy<int, string, double>(); 
-      Fanxing.LeiXing_2[1] = "ABSD"; +         
-      Fanxing.LeiXing_3[1] = 63.588;+        Fanxing.LeiXing_1[1] = 500;      // T is int 
 +        Fanxing.LeiXing_2[1] = "ABSD";   // U is string 
 +        Fanxing.LeiXing_3[1] = 63.588;   // F is double 
 +    }
 } }
 +
 +// 多样化泛型类
 +class reyy<T, U, F>
 +{   
 +    public T[] LeiXing_1 = new T[300];
 +    public U[] LeiXing_2 = new U[300];
 +    public F[] LeiXing_3 = new F[300];
 } }
 +</code>
  
-        //多样化泛型类 +===== 5. 泛型的继承 =====
-        class reyy<T , U , F> +
-        {    +
-            public T[] LeiXing_1 new T[300]; +
-            public U[] LeiXing_2 new U[300]; +
-            public F[] LeiXing_3 new F[300]; +
-        } +
-```+
  
-泛型的继承-1普通类继承泛型+泛型类也可以被继承,主要分为两种情况。
  
-泛型可以被继承 +==== 情况 1普通类继承泛型 ====
-例如:继承时特化泛型类型 +
-``` +
-    class Program +
-    { +
-        static void Main(string[] args) +
-        { +
-            teacher Teacher new teacher();//实例化老师对象 +
-            Teacher.id 550346;//老师作为人类的id +
-        }+
  
-    } +在继承时,直接**特化**泛型类型(确定父类的类型)。 
-    class people<T>+ 
 +<code csharp> 
 +class Program 
 +
 +    static void Main(string[] args)
     {     {
-        //编号属性 +        teacher Teacher = new teacher(); // 实例化老师对象 
-        public T id { getset; } +        Teacher.id = 550346// 老师作为人类的 id (已经是 int 类型)
     }     }
-    class teacher : people<int>  +}
-    //继承一个泛型父类、继承的同时特化泛型 +
-    { +
-    } +
-```+
  
-# 泛型的继承-2泛型继承泛型+class people<T> 
 +
 +    // 编号属性 
 +    public T id { get; set; }  
 +}
  
-泛型继承泛型、当子类被实例化时特化的类也会传导给父类 +// 继承一个泛型父类继承的同时特化为 int 
-``` +class teacher : people<int>  
-    class Program +{ 
-    { +
-        static void Main(string[] args) +</code>
-        { +
-            teacher<int> Teacher = new teacher<int>();//实例化老师对象 +
-                                                      //把子类特化int类型传导给父类T +
-            Teacher.id = 550346;//老师作为人类的id +
-        +
-    }+
  
-    class people<T>+==== 情况 2:泛型继承泛型 ==== 
 + 
 +子类也是泛型,当子类被实例化时,特化的类型会**传导**给父类。 
 + 
 +<code csharp> 
 +class Program 
 +
 +    static void Main(string[] args)
     {     {
-        //编号属性 +        // 实例化老师对象,特化为 int 
-        public T id { getset; } +        // 把子类特化 int 类型传导给父类 T 
 +        teacher<int> Teacher = new teacher<int>(); 
 +         
 +        Teacher.id = 550346// 老师作为人类的 id
     }     }
-    class teacher<B> : people<B> +}
-    { +
-        //当无法确定子类的类型时、可以把子类看做泛型类、 +
-        //当子类实例化时、特化的类型B也会传导给父类T +
-    } +
-``` +
-# 总结+
  
-{{.:pasted:20250928-163412.png}}+class people<T> 
 +{ 
 +    // 编号属性 
 +    public T id get; set;  
 +}
  
 +// 当无法确定子类的类型时、可以把子类看做泛型类
 +// 当子类实例化时、特化的类型 B 也会传导给父类 T
 +class teacher<B> : people<B>
 +{
 +}
 +</code>
  
 +===== 6. 泛型约束 (Constraints) =====
  
 +默认情况下,泛型 ''T'' 可以是任何类型。但在某些场景下,我们需要限制 ''T'' 必须具备某些特征(例如:必须是引用类型、必须实现了某个接口、或者必须有一个无参构造函数)。
  
 +这时就需要使用 **''where''** 关键字。
  
 +==== 常用约束列表 ====
  
 +^ 约束语法 ^ 说明 ^
 +| ''where T : struct'' | 类型参数必须是**值类型** (如 int, float, struct)。 |
 +| ''where T : class'' | 类型参数必须是**引用类型** (如 string, class, interface)。 |
 +| ''where T : new()'' | 类型参数必须有一个**无参数的公共构造函数**。此约束允许在泛型类中创建 T 的实例 (''new T()'')。 |
 +| ''where T : <基类名>'' | 类型参数必须是指定的基类,或者是派生自该基类的子类。 |
 +| ''where T : <接口名>'' | 类型参数必须实现指定的接口。 |
  
 +==== 示例代码 ====
 +
 +<code csharp>
 +// 1. 接口约束示例
 +// 只有实现了 IDBItem 接口的类,才能作为 T 传入
 +public bool IsExist<T>(string TableName = null) where T : IDBItem
 +{
 +    // 因为加了约束,编译器知道 T 一定有 IDBItem 的特性
 +    return true;
 +}
 +
 +// 2. 构造函数约束示例
 +// 只有包含无参构造函数的类,才能作为 T 传入
 +class Factory<T> where T : new()
 +{
 +    public T CreateInstance()
 +    {
 +        // 如果没有 new() 约束,这里写 new T() 会报错
 +        return new T(); 
 +    }
 +}
 +
 +// 3. 组合约束
 +// T 必须同时满足:是引用类型、实现了 IDisposable 接口、且有无参构造函数
 +class MyManager<T> where T : class, IDisposable, new()
 +{
 +}
 +</code>
  
 +===== 7. 总结 =====
  
 +{{.:pasted:20250928-163412.png?500|泛型总结示意图}}

该主题尚不存在

您访问的页面并不存在。如果允许,您可以使用创建该页面按钮来创建它。

  • csharp/类/泛型.1759048658.txt.gz
  • 最后更改: 2025/09/28 16:37
  • 张叶安