c#中泛型的学习
c#泛型入门简介
在c#中,我们通常用泛型来处理某个类或方法。比如某个方法要实现某个功能,但 参数的类型不同,我们可以采用重载方法来实现,但这个方法就要重复定义很多遍,所以为了高效,我们可以采用泛型。
1 泛型方法
首先来看一下不用泛型来实现某个功能
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyGeneric
{
/// <summary>
/// 普通方法
/// </summary>
public class CommonMethod
{
/// <summary>
/// int类型参数
/// 参数类型是写死的
/// </summary>
/// <param name="iParameter"></param>
public static void ShowInt(int iParameter)
{
Console.WriteLine("This is ShowInt, parameter={0} type={1}", iParameter, iParameter.GetType());
}
/// <summary>
/// string类型参数
/// </summary>
/// <param name="sParameter"></param>
public static void ShowString(string sParameter)
{
Console.WriteLine("This is ShowString, parameter={0} type={1}", sParameter, sParameter.GetType());
}
/// <summary>
/// DateTime类型参数
/// </summary>
/// <param name="dtParameter"></param>
public static void ShowDateTime(DateTime dtParameter)
{
Console.WriteLine("This is ShowDateTime, parameter={0} type={1}", dtParameter, dtParameter.GetType());
}
/// <summary>
/// object类型参数
/// 1 object是一切类型的父类
/// 2 通过继承,子类可以拥有父类的一切属性和行为,任何父类出现的地方,都可以用子类来代替
/// </summary>
/// <param name="dtParameter"></param>
public static void ShowObject(object oParameter)
{
Console.WriteLine("This is ShowObject, parameter={0} type={1}", oParameter, oParameter.GetType());
}
}
}
在这个类中,我们主要是为了输出显示某个变量,但这些变量的数据类型不同,所以我们就要定义多个功能类似的方法来适应不用类型的参数。这样虽然实现了我们想要的功能,但是太过繁琐,我们可以通过使用泛型将这几个方法合并成一个就可以实现这些功能。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyGeneric
{
public class GenericMethod
{
/// <summary>
/// 泛型
/// 参数类型可变的
/// 类型在调用的时候确定
///
/// 延迟思想:推迟一切可以推迟的
///
/// 怎么实现的:.net framework 2.0 编译器升级
/// 升级了jit
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tParameter"></param>
public static void Show<T>(T tParameter)
{
Console.WriteLine("This is Show<T>, parameter={0} type={1}", tParameter, tParameter.GetType());
}
}
这就是采用泛型来定义的方法。上述定义的是泛型方法。与定义普通方法最大的不同就是在方法名后多了<T>
这里的T可以代表任何的数据类型,不管是之类型还是引用类型,当在用泛型定义方法时,因为不确定参数的数据类型,所以就用T来代表某种数据类型的名称,当代码在编译时确定T所具体指代的数据类型。
我们再来学习如何调用泛型方法
GenericMethod.Show<object>(oValue);
GenericMethod.Show<int>(iValue);
GenericMethod.Show<int>(sValue);//类型参数和参数类型必须一致
GenericMethod.Show(iValue);
GenericMethod.Show<string>(sValue);
GenericMethod.Show<DateTime>(dtValue);
与调用普通方法不同的是,在调用泛型方法时,在方法名和方法参数间要加上<typeparam>
用来指定在调用该方法时T具体代表的数据类型。
2 泛型类
首先我们采用普通方法
namespace Wrox.ProCSharp.Generics
{
public class LinkedListNode
{
public LinkedListNode(object value)
{
Value = value;
} public object Value { get; }
public LinkedListNode Next { get; internal set; }
public LinkedListNode Prev { get; internal set; }
}
}`
using System.Collections;
namespace Wrox.ProCSharp.Generics
{
public class LinkedList : IEnumerable
{
public LinkedListNode First { get; private set; }
public LinkedListNode Last { get; private set; }
public LinkedListNode AddLast(object node)
{
var newNode = new LinkedListNode(node);
if (First == null)
{
First = newNode;
Last = First;
}
else
{
Last.Next = newNode;
Last = newNode;
}
return newNode;
}
public IEnumerator GetEnumerator()
{
LinkedListNode current = First;
while (current != null)
{
yield return current.Value;
current = current.Next;
}
}
}
}
using static System.Console;
namespace Wrox.ProCSharp.Generics
{
class Program
{
static void Main()
{
var list1 = new LinkedList();
list1.AddLast(2);
list1.AddLast(4);
// list1.AddLast(“6”);
foreach (int i in list1)
{
WriteLine(i);
}
}
}
}
接下来我们再来采用泛型类来实现
namespace Wrox.ProCSharp.Generics
{
public class LinkedListNode<T>
{
public LinkedListNode(T value)
{
Value = value;
}
public T Value { get; }
public LinkedListNode<T> Next { get; internal set; }
public LinkedListNode<T> Prev { get; internal set; }
}
}
using System.Collections;
using System.Collections.Generic;
namespace Wrox.ProCSharp.Generics
{
public class LinkedList : IEnumerable
{
public LinkedListNode First { get; private set; }
public LinkedListNode Last { get; private set; }
public LinkedListNode<T> AddLast(T node)
{
var newNode = new LinkedListNode<T>(node);
if (First == null)
{
First = newNode;
Last = First;
}
else
{
Last.Next = newNode;
Last = newNode;
}
return newNode;
}
public IEnumerator<T> GetEnumerator()
{
LinkedListNode<T> current = First;
while (current != null)
{
yield return current.Value;
current = current.Next;
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}
using static System.Console;
namespace Wrox.ProCSharp.Generics
{
class Program
{
static void Main()
{
var list2 = new LinkedList();
list2.AddLast(1);
list2.AddLast(3);
list2.AddLast(5);
foreach (int i in list2)
{
WriteLine(i);
}
var list3 = new LinkedList<string>();
list3.AddLast("2");
list3.AddLast("four");
list3.AddLast("foo");
foreach (string s in list3)
{
WriteLine(s);
}
}
}
}
定义泛型类也就是在定义类时要在类名后加上<T>,然后咋定义类的细节时,用T来代替不确定的数据类型名称,当然在实例化一个对象时也要额外地加上T具体代表的数据类型。
使用泛型可避免拆包和装包时的性能损失。
3 泛型约束
泛型约束是在在定义泛型类时,对T所指代的数据类型的约束。通过添加where
语句来实现
“具体含义如下表所示
接下来介绍下具体的实现代码
例如声明一个泛型类,T必须是引用类型,切必须有默认构造函数
class myClass<T>
where T : struct, new()
{
}
c#的泛型就介绍到这,这只是泛型的入门,大家学习完以上内容后可再学习一下相关书籍上的有关内容。