【从零开始入门unity游戏开发之——C#篇29】C#泛型(T)和 泛型约束

文章目录

一、泛型

1、泛型是什么

泛型是通过类型参数化来实现代码重用的机制。它允许你在编写类或方法时,使用类型占位符(通常是一个字母),并在实际使用时指定具体的类型。泛型使得同一份代码能够处理多种类型,提高了代码的灵活性和可维护性。

2、泛型分类

2.1. 泛型类和泛型接口

csharp 复制代码
// 泛型类的基本语法:
class ClassName<T> { }

// 泛型接口的基本语法:
interface InterfaceName<T> { }

2.2. 泛型方法

csharp 复制代码
// 泛型方法的基本语法:
ReturnType MethodName<T>(Parameters) { }
// 可以有多个泛型参数
ReturnType MethodName<T1, T2>(Parameters) { }

3、泛型类和接口

3.1 泛型类示例:

csharp 复制代码
class TestClass<T>
{
    public T value;
}

// 使用泛型类时指定类型
TestClass<int> t1 = new TestClass<int>();
t1.value = 10;
Console.WriteLine(t1.value); // 输出: 10

TestClass<string> t2 = new TestClass<string>();
t2.value = "Hello";
Console.WriteLine(t2.value); // 输出: Hello

3.2 泛型接口示例:

csharp 复制代码
interface ITestInterface<T>
{
    T Value { get; set; }
}

class Test : ITestInterface<int>
{
    public int Value { get; set; }
}

3.3 泛型类接受多个类型参数:

csharp 复制代码
class TestClass2<T1, T2, T3>
{
    public T1 Value1;
    public T2 Value2;
    public T3 Value3;
}

TestClass2<int, string, float> test = new TestClass2<int, string, float>();
test.Value1 = 10;
test.Value2 = "Test";
test.Value3 = 3.14f;

4、泛型方法

4.1. 普通类中的泛型方法

csharp 复制代码
class Test
{
    public void TestMethod<T>(T value)
    {
        Console.WriteLine(value);
    }
}

Test test = new Test();
test.TestMethod<int>(10); // 输出: 10
test.TestMethod<string>("Hello"); // 输出: Hello

4.2. 泛型类中的泛型方法

csharp 复制代码
class TestClass<T>
{
    public void TestMethod<K>(K value)
    {
        Console.WriteLine(value);
    }
}

TestClass<int> test = new TestClass<int>();
test.TestMethod<string>("Test Method");

5、泛型的作用

  • 相同逻辑处理不同类型的对象:泛型可以用来编写处理不同类型对象的相同逻辑的代码,避免重复编写相似的代码。

  • 避免装箱拆箱 :泛型可以避免值类型(如 int)在集合类(如 ArrayList)中进行装箱拆箱操作,减少性能开销。

6、总结

  • 泛型是一个类型占位符,在编写代码时并不指定具体类型,直到使用时再指定。
  • 泛型的类型占位字母可以有多个,并用逗号分开。
  • 泛型占位字母通常是大写字母(如 TKV 等)。
  • 不确定泛型类型时,获取默认值,可以使用 default(T) 获取类型的默认值。
  • 看到<>包括的字母,那肯定是泛型。

二、泛型约束

在 C# 中,泛型约束用于限制泛型类型参数必须满足的条件。这使得泛型代码更加灵活和类型安全,同时避免了某些运行时错误。通过泛型约束,可以确保泛型类型参数遵循特定的行为或者接口,增强代码的可预测性和可靠性。

1、基本的泛型约束

泛型约束是在泛型声明中通过 where 关键字定义的,基本的语法如下:

csharp 复制代码
class ClassName<T> where T : Constraint
{
    // T 是满足 Constraint 的类型
}

2、各泛型约束详细讲解

2.1. 值类型约束(struct

  • 该约束要求泛型类型参数是值类型,不能是引用类型。
  • 常见的值类型有:int, float, double, struct 自定义值类型。
csharp 复制代码
class Test1<T> where T : struct
{
    public T value;
    public void TestFun<K>(K y) where K : struct
    {
        // 只能传入值类型
    }
}

// 使用示例
Test1<int> t1 = new Test1<int>();
t1.TestFun<float>(1.3f);  // 可以传递float,因为float是值类型

2.2. 引用类型约束(class

  • 该约束要求泛型类型参数是引用类型,可以是任何类、接口或委托类型。
csharp 复制代码
class Test2<T> where T : class
{
    public T value;
    public void TestFun<K>(K y) where K : class
    {
        // 只能传入引用类型
    }
}

// 使用示例
Test2<Random> t2 = new Test2<Random>();
t2.value = new Random();
t2.TestFun<object>(new object());  // 可以传递object,因为它是引用类型

2.3. 公共无参构造函数约束(new()

  • 该约束要求泛型类型参数必须具有公共无参构造函数,可以在代码中使用 new() 创建实例。
csharp 复制代码
class Test3<T> where T : new()
{
    public T value;
    public Test3()
    {
        value = new T();  // 创建T类型的实例
    }
}

class Test1 { }

Test3<Test1> t3 = new Test3<Test1>();  // Test1必须有公共无参构造函数

补充知识

类的无参构造函数知识点你可能已经忘记了,这里补充一下。

在 C# 中,默认情况下每个类都会有一个 隐式无参构造函数,如果你没有显式地定义构造函数。也就是说,在你声明一个空的类 Test1 时,它会自动获得一个无参构造函数,虽然你没有写出这个构造函数。

csharp 复制代码
class Test1
{
    // 这里没有显式写构造函数
}

上面的代码实际上等价于:

csharp 复制代码
class Test1
{
    // 默认无参构造函数
    public Test1() { }
}

如果你在类中显式定义了其他构造函数(例如带参数的构造函数),那么编译器 不会 自动生成无参构造函数。此时,如果你需要无参构造函数,必须显式地提供。

例如,以下代码就不会自动提供无参构造函数:

csharp 复制代码
class Test1
{
    public Test1(int x) { }  // 显式定义了带参数的构造函数
}

如果你希望仍然能够使用无参构造函数,你需要显式定义它:

csharp 复制代码
class Test1
{
    public Test1() { }  // 显式定义无参构造函数
    public Test1(int x) { }  // 仍然可以有带参数的构造函数
}

2.4. 类约束(BaseClass

  • 该约束要求泛型类型参数必须是某个类及其派生类。
csharp 复制代码
class Test4<T> where T : Test1
{
    public T value;
}

class Test3 : Test1 { }

Test4<Test3> t4 = new Test4<Test3>();  // Test3是Test1的派生类

2.5. 接口约束(IInterface

  • 该约束要求泛型类型参数实现某个接口。
csharp 复制代码
interface IFly { }

class Test4 : IFly { }

class Test5<T> where T : IFly
{
    public T value;
}

Test5<Test4> t5 = new Test5<Test4>();  // Test4实现了IFly接口

2.6. 另一个泛型约束(T : U

  • 该约束要求泛型类型 T 必须是另一个泛型类型 U 或其派生类。
csharp 复制代码
class Test6<T, U> where T : U
{
    public T value;
}

class Test4 { }

Test6<Test4, object> t6 = new Test6<Test4, object>();  // Test4是object的派生类

3、泛型约束的组合使用

泛型约束可以组合使用,这样可以同时限制多个条件。多个约束用 where 关键字连接。

csharp 复制代码
class Test7<T> where T : class, new()  // T必须是引用类型并且有公共无参构造函数
{
    public T value;
}

class Test8<T, K> where T : class, new() where K : struct  // T需要满足引用类型并有构造函数,K是值类型
{
    public T value;
    public K key;
}

4、总结

  • 泛型约束使得我们可以对泛型类型参数进行类型限制,从而避免运行时错误,增强类型安全。
  • 常见的泛型约束包括:class, struct, new(), 类名、接口名以及其他泛型类型。
  • 这些约束可以组合使用,确保泛型类型参数在特定的约束范围内。

通过合理使用泛型约束,开发者可以确保程序在不同类型数据处理时的一致性和安全性。


专栏推荐

地址
【从零开始入门unity游戏开发之------C#篇】
【从零开始入门unity游戏开发之------unity篇】
【制作100个Unity游戏】
【推荐100个unity插件】
【实现100个unity特效】
【unity框架开发】

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!如果你遇到任何问题,也欢迎你评论私信或者加群找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~

相关推荐
ou.cs3 分钟前
c# 快捷键模块
c#
唐棣棣4 分钟前
期末速成C++【知识点汇总完】
开发语言·c++
yannan201903139 分钟前
【数据结构】(Python)差分数组。差分数组与树状数组结合
开发语言·python·算法
中國移动丶移不动11 分钟前
Java List 源码解析——从基础到深度剖析
java·后端·list
belldeep1 小时前
C#:多线程 简单示例
c#·多线程·thread
Java知识技术分享1 小时前
spring boot 异步线程池的使用
java·spring boot·spring
m0_748232921 小时前
Springboot3.x整合swagger3
java
东林知识库1 小时前
Mysql高级
java·mysql
m0_748248231 小时前
Springboot项目:使用MockMvc测试get和post接口(含单个和多个请求参数场景)
java·spring boot·后端
顾北辰201 小时前
基本算法——回归
java·spring boot·机器学习