C#基础——泛型、泛型约束、泛型默认值

泛型

  • 正常定义数据的时候需要知道当前的类型,必须传入执行的类型,才可以正常编译
  • 而使用泛型则可以在编写代码时使用未确定的类型

泛型允许编写可以适用于多种数据类型的类、接口和方法。通过泛型,你可以编写更加灵活、可重用的代码。

定义泛型方法

public class MyClass {
	public void MyClassMethod<T>(T a) { //尖括号代表了泛型的数据类型,A是类型名称,a是参数
  		//只有在使用该方法的时候,才会根据赋值确定当前A的类型。
  		Console.WriteLine(a);
	}
}

 MyClass myClass = new MyClass();
//泛型可以代表任意数据类型
myClass.MyClassMethod(100);
myClass.MyClassMethod<string>("100");
myClass.MyClassMethod<bool>(false);
myClass.MyClassMethod2<string>("我是字符串类型");
myClass.MyClassMethod2<int>(123);

方法的返回值也可以使用泛型进行定义

public T MyClassMethod3<T>(T a, T b) {
  //如果a==b则返回a,否则返回b
  //因为在这里代码还不确定是什么类型, == 需要知道里面的值,泛型是先声明后赋值操作
  if (a.Equals(b)) {
    return a;
  } else {
    return b;
  }
}

//泛型的数据类型取决于开发者
Console.WriteLine(myClass.MyClassMethod3<int>(1, 2));
Console.WriteLine(myClass.MyClassMethod3<int>(2, 2));
Console.WriteLine(myClass.MyClassMethod3<string>("叽里呱啦a", "叽里呱啦b"));

泛型方法也可以传入多个泛型

//多个泛型 
public void MyClassMethod4<T, D>(T a, D d) {
   Console.WriteLine(a.GetType().ToString());
   Console.WriteLine(d.GetType().ToString());
 }

 //多个泛型
 myClass.MyClassMethod4<int, string>(100, "第二个泛型");
 //泛型也可以是对象当作泛型的类型
 People people = new People();
 people.Name = "我是对象";
 myClass.MyClassMethod4<People, string>(people, "第二个泛型");

泛型接口是一种可以定义参数化类型的接口,它可以用来描述对一组类型的操作,而不需要具体指定这些类型。

通过使用泛型接口,可以实现更灵活和通用的代码设计。

定义一个泛型接口

public interface InterfaceTest<T> {
  //test1 属性名
  T test1 { get; set; } //为将来继承自接口的类,提供了一个泛型属性
  string test2 { get; set; }
  void InterfaceTestMethod();
}

被泛型接口继承的类,在继承的时候需要明确接口的泛型类型

//如果是从泛型接口继承的,那么在继承的时候就需要告知当前接口的泛型类型
public class MyClass : InterfaceTest<int> {
  public int test1 { get; set; }
  public string test2 { get; set; }
  public void InterfaceTestMethod() {
    Console.WriteLine("该方法是从泛型继承过来的方法。");
  }
}

 MyClass myClass = new MyClass();
 myClass.test1 = 100;
 myClass.test2 = "小明";
 myClass.InterfaceTestMethod();
 Console.WriteLine($"{myClass.test2}考了:{myClass.test1}分");

被继承的泛型接口在使用的时候要明确泛型的类型

 public interface InterfaceTest2<D> : InterfaceTest<string> {
   D boom1 { get; set; }
   void InterfaceMethod2(D dd);
 }

//完成对 InterfaceTest2 的继承
public class MyClass2 : InterfaceTest2<int> {
  //如果类继承的接口还有其他的接口继承,那么是需要都实现的
  public int boom1 { get; set; }
  public void InterfaceMethod2(int dd) {
    Console.WriteLine("该方法是从泛型接口2继承过来的方法。", dd);
  }
  public string test1 { get; set; }
  public string test2 { get; set; }
  public void InterfaceTestMethod() {
    Console.WriteLine("该方法是从泛型接口1继承过来的方法。");
  }
}

MyClass2 myClass2 = new MyClass2();
myClass2.boom1 = 100;
myClass2.InterfaceMethod2(myClass2.boom1);

泛型约束

用于对泛型参数进行限制,以确保泛型参数满足特定的条件。泛型约束可以应用于泛型类、方法、接口和委托。

1、struct 约束:使用 struct 关键字可以确保泛型参数必须是值类型。

public class MyClass<T> where T : struct {
  public T value { get; set; }
}

 MyClass<int> m1 = new MyClass<int>();
 m1.value = 1;
 //MyClass<Array> m2 = new MyClass<Array>(); 这句代码被约束了
 Console.WriteLine(m1.value);

2、class约束:使用calss关键字可以确保泛型类型必须是引用类型(类、接口、委托或数组),而不能是值类型

 public class MyClass2<T> where T : class {
   public T obj { get; set; }
 }
//再创建一个类
public class Test { public string name; }
 
 MyClass2<Test> t1 = new MyClass2<Test>();
 //注意:这里的obj因为用了泛型,而泛型T现在是Test引用类型 ,那么obj肯定是对象。
 Console.WriteLine(t1.obj); //空
 t1.obj = new Test();
 t1.obj.name = "张三";
 Console.WriteLine(t1.obj.name); //张三 

3、class? 可为空引用类型约束:参数的值可以为null或不为null的引用类型

public class MyClass3<T> where T : class? { }

4、notnull 不能为空约束:代表不能为null的引用类型,也可以表示不能为null的值类型

public class MyClass4<T> where T : notnull { }

5、new() 构造函数约束:必须是公共无参数构造函数

public class MyClass5<T> where T : new() {
     // 当前传入的引用类型对象必须是可以用无参公共构造函数能够创建的才可以
     public T value;
}
public class Test2 {
  public Test2() {
    Console.WriteLine("我是公共无参数的构造函数test2");
  }
}

MyClass5<Test2> m5 = new MyClass5<Test2>();
m4.value = new Test2();
string str1 = "abcdefg";
string str2 = new string('c', 20);

6、多个约束放到一处

public class MyClass6<T, D> where T : class where D : struct {
	public T obj { get; set; }
    public D sum { get; set; }
}

//多个约束放在一处
//第一个参数约束Class,那么就表示在使用的时候需要赋值为引用类型
//第二个参数约束int,表示在使用的时候需要引入int值数据
MyClass3<Test, int> m3 = new MyClass3<Test, int>();
//已经确定了obj数据Test
//num属于int类型
m3.obj = new Test(); //要根据泛型的实际类型来为属性赋值
m3.obj.name = "Test";
m3.sum = 100;

7、可以对单一的泛型进行多个约束(可控),多个约束,new()要放在最后面,不能和struct和unmanaged(非托管约束)一起使用

public class MyClass5<T> where T : class, new() {
  public T Value;
}
public interface IFly {
  void fly();
}
public class Test3 : IFly {
  public void fly() {
    Console.WriteLine("实现了fly的会飞方法。");
  }
}

MyClass5<Test3> m5 = new MyClass5<Test3>();

泛型默认值(default)

当使用泛型类型时,如果需要一个默认值,可以使用 default(T) 来获取泛型类型的默认值。这个 default(T) 表达式会根据类型参数 T 的实际类型返回一个合适的默认值。

public class TestDefault<T> {
  //带有返回值的方法
  public T foo() {
    //因为在return的时候需要知道当前类型的具体值,但是泛型属于后引用,所以在这里通过default方法返回默认值
    return default(T);
  }
}

TestDefault<int> testDefault = new TestDefault<int>();
var result = testDefault.foo();
//值类型默认值是0,引用类型是null,布尔值的默认值是false,字符和字符串都是空字符 ‘\0’ “”
Console.WriteLine("这是个:" + result +"类型。");

泛型的特点:
提高代码的安全性和可读性:泛型可以在编译时进行类型检查,避免了类型转换错误,提高了代码的安全性。同时,泛型的类型参数可以提供更具有描述性的命名,增加代码的可读性。
提高代码的重用性:通过使用泛型,可以编写通用的算法和数据结构,使其适用于多种数据类型,从而提高代码的重用性。
简化代码:使用泛型可以减少代码的冗余,避免了为每种数据类型编写相似的代码。

相关链接:泛型约束总结

  • 18
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
C#中,可以使用泛型来指定一个类的基类,同时也可以使用泛型约束来限制泛型类型参数的类型。通过泛型的基类和泛型约束,可以实现更加灵活和可复用的代码。 以下是一个示例代码,演示了如何定义一个泛型类,并指定其基类以及泛型约束: ```csharp public class MyBaseClass { public void BaseMethod() { Console.WriteLine("BaseMethod called."); } } public class MyGenericClass<T> : MyBaseClass where T : SomeType { public void GenericMethod(T item) { Console.WriteLine("GenericMethod called."); // 可以访问 MyBaseClass 中的成员 BaseMethod(); // 可以使用 T 类型的参数 item 进行操作 Console.WriteLine($"Item: {item}"); } } ``` 在上面的示例中,`MyBaseClass` 是一个基类,`BaseMethod` 是其成员方法。`MyGenericClass<T>` 是一个泛型类,泛型类型参数 `T` 受到 `SomeType` 泛型约束限制,并且继承自 `MyBaseClass`。在 `MyGenericClass<T>` 中,可以访问 `MyBaseClass` 的成员方法,并且使用 `T` 类型的参数进行操作。 使用示例代码: ```csharp MyGenericClass<int> instance = new MyGenericClass<int>(); instance.GenericMethod(42); ``` 在上面的代码中,我们创建了一个 `MyGenericClass<int>` 的实例,并调用了 `GenericMethod` 方法,传入了整数类型的参数 `42`。输出结果如下: ``` GenericMethod called. BaseMethod called. Item: 42 ``` 总结起来,通过在泛型类中指定基类和泛型约束,可以使泛型类继承自指定的基类,并对泛型类型参数进行类型约束,提供更加灵活和可复用的代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值