跳转到内容

C Sharp/Generics

维基教科书,自由的教学读本

泛型(Generics)是C# 2.0引入的特性。支持了类型作为参数。最常见的使用情形是创建collection类。泛型极大化了代码重用、类型安全和性能。[1]

泛型类

[编辑]

如果想创建一个支持各种类型的容器,如下例:

public class SomeObjectContainer
{
    private object _obj;

    public SomeObjectContainer(object obj)
    {
        this._obj = obj;
    }

    public object GetObject()
    {
        return this._obj;
    }
}

使用该容器:

class Program
{
    static void Main(string[] args)
    {
        SomeObjectContainer container = new SomeObjectContainer(25);
        SomeObjectContainer container2 = new SomeObjectContainer(5);

        Console.WriteLine((int) container.GetObject() + (int) container2.GetObject());
        Console.ReadKey(); // wait for user to press any key, so we could see results
    }
}

可见看到用值类型的值初始化该容器,需要“自动装箱”(autoboxing),使用时还需要类型转化为整数。这些都是性能惩罚。使用泛型,不仅可以优化性能,还实现了类型安全。如下例:

public class GenericObjectContainer<T>
{
    private T _obj;

    public GenericObjectContainer(T obj)
    {
        this._obj = obj;
    }

    public T getObject()
    {
        return this._obj;
    }
}

使用这个泛型类:

class Program
{
    static void Main(string[] args)
    {
        GenericObjectContainer<int> container = new GenericObjectContainer<int>(25);
        GenericObjectContainer<int> container2 = new GenericObjectContainer<int>(5);
        Console.WriteLine(container.getObject() + container2.getObject());

        Console.ReadKey(); // wait for user to press any key, so we could see results
    }
}


泛型接口

[编辑]
public interface IContainer<T>
{
    T GetObject();
    void SetObject(T value);
}

public class StringContainer : IContainer<string>
{
    private string _str;
    
    public string GetObject()
    {
        return _str;
    }
    
    public void SetObject(string value)
    {
        _str = value;
    }
}

public class FileWithString : IContainer<string>
{
    ...
}

class Program
{
    static void Main(string[] args)
    {
        IContainer<string> container = new StringContainer();
        
        container.SetObject("test");

        Console.WriteLine(container.GetObject());
        container = new FileWithString();

        container.SetObject("another test");

        Console.WriteLine(container.GetObject());
        Console.ReadKey();
    }
}

List<T>类和LinkedList<T>类,都声明在System.Collections.Generic命名空间,实现了IEnumerable<T>接口。List<T>的一个构造函数基于实现了IEnumerable<T>接口的对象构造一个List,如下例:

LinkedList<int> linkedList = new LinkedList<int>();

linkedList.AddLast(1);
linkedList.AddLast(2);
linkedList.AddLast(3);
// linkedList now contains 1, 2 and 3.

List<int> list = new List<int>(linkedList);

// now list contains 1, 2 and 3 as well!

泛型方法

[编辑]
using System;
using System.Collections.Generic;

public static bool ArrayContains<T>(T[] array, T element)
{
    foreach (T e in array)
    {
        if (e.Equals(element))
        {
            return true;
        }
    }

    return false;
}

可用于搜索任何类型的数组:

using System;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
        string[] strArray = { "string one", "string two", "string three" };
        int[] intArray = { 123, 456, 789 };
        
        Console.WriteLine(ArrayContains<string>(strArray, "string one")); // True
        Console.WriteLine(ArrayContains<int>(intArray, 135)); // False
    }
}

类型约束

[编辑]

可明确指出泛型的类型参数的约束条件。如下例:

public class MyClass<T, U, V, W>
    where T : class,        // T should be a reference type (array, class, delegate, interface)
        new()               // T should have a public constructor with no parameters
    where U : struct        // U should be a value type (byte, double, float, int, long, struct, uint, etc.)
    where V : MyOtherClass, // V should be derived from MyOtherClass
        IEnumerable<U>      // V should implement IEnumerable<U>
    where W : T,            // W should be derived from T
        IDisposable         // W should implement IDisposable
{
    ...
}


参考文献

[编辑]
  1. Generics (C# Programming Guide).msdn.于2011年8月9日查阅.