C# 泛型(4) 持续更新

泛型可以创建独立于被包含类型的类和方法。

C++模板与泛型相似。

泛型优点性能

System.Collections 和 System.Collections.Generic

名称空间泛型和非泛型集合类。

值类型存储在栈上,引用类型存储在堆上。C#类是引用类型,结构是值类型。

从值类型转化为引用类型称为装箱。方法需要把一个对象作为参数,传递了一个值类型,装箱操作就会自动进行。

装箱的值类型可以使用拆箱操作转换为值类型。在拆箱时,需要使用类型强制转换运算符。

ArrayList list = new ArrayList();
list.Add(4);

int i1 = (int) list[0];

foreach (int i2 in list)
{
    Console.WriteLine(i2);
}

装箱和拆箱操作很容易使用,但性能损失比较大,遍历尤其如此。

List<T> 泛型类,不再进行装箱和拆箱操作

List<int> list = new List<int>();
list.Add(4);

int i1 = list[0];

foreach (int i2 in list)
{
    Console.WriteLine(i2);
}

类型安全

ArrayList

ArrayList list = new ArrayList();
list.Add(4);
list.Add("mystring");
list.Add(new ArrayList());

foreach (int i2 in list)
{
    Console.WriteLine(i2);
}

并不是所有元素都可以强制转换int。所以运行抛出异常。

错误应尽早发现。List<T> 泛型类就不会。

 List<int> list = new List<int>();
 list.Add(4);
 list.Add("mystring");
 list.Add(new ArrayList());

直接在编译前,就报错。

二进制代码重用

List<Byte> list = new List<Byte>();
list.Add(4);

List<string> list2 = new List<string>();
list2.Add("hello");

代码的扩展

引用类型在实例化的泛型类中只需要4个字节的内存地址(32位系统),就可以引用一个引用类型。值类型包含在实例化的泛型类的内存中,因为每个值类型对内存的要求不同,所以值类型实例化新类。

命名约定

  • 泛型类行的名称用字母T作为前缀。
  • 如果没有特殊要求,泛型类型允许用任意类替代,且只使用一个泛型类型,就可以用字符T作为泛型类型名称。
 public class LinkedList<T>
 {
     
 }
  • 如果泛型类型有特定要求(如实现一个接口或派生自基类),或者使用了两个或多个泛型类型。就应给泛型类型使用描述性的名称:
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);

创建泛型类

一个非泛型的列表类。

public class LinkedListNode
{
    public LinkedListNode(object value)
    {
        this.Value = value;
    }

    public object Value { get; private set; }

    public LinkedListNode Next { get; internal set; }
    public LinkedListNode Prev { get; internal set; }
}

public class LinkedList : IEnumerable
{
    public LinkedListNode First { get; private set; }
    public LinkedListNode Last { get; private set; }

    public LinkedListNode AddLast(object node)
    {
        LinkedListNode newNode = new LinkedListNode(node);

        if (First == null)
        {
            First = newNode;
            Last = First;
        }
        else
        {
            LinkedListNode previous = Last;
            Last.Next = newNode;
            Last = newNode;
            Last.Prev = previous;
        }
        return newNode;
    }

    public IEnumerator GetEnumerator()
    {
        LinkedListNode current = First;
        while (current != null)
        {
            yield return current.Value;
            current = current.Next;
        }
    }
}

yield语句创建一个枚举器的状态机。

 LinkedList _linked = new LinkedList();
 _linked.AddLast(2);
 _linked.AddLast(4);
 _linked.AddLast("6");

 foreach (int i2 in _linked)
 {
     Console.WriteLine(i2);
 }

改成泛型类

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplicationCShape
{
    public class LinkedListNode<T>
    {
        public LinkedListNode(T value)
        {
            this.Value = value;
        }

        public T Value { get; private set; }
        public LinkedListNode<T> Next { get; internal set; }
        public LinkedListNode<T> Prev { get; internal set; }
    }

    public class LinkedList<T> : IEnumerable<T>
    {
        public LinkedListNode<T> First { get; private set; }
        public LinkedListNode<T> 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()
        {
            return GetEnumerator();
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            LinkedList<int> _linked = new LinkedList<int>();
            _linked.AddLast(2);
            _linked.AddLast(4);
            _linked.AddLast(6);

            foreach (int i2 in _linked)
            {
                Console.WriteLine(i2);
            }

            Console.ReadLine();
        }
    }
}

泛型类的功能

泛型文档类管理

class DocumentManage<T>
{
    private readonly Queue<T> documentQueue = new Queue<T>();

    public void AddDocument(T doc)
    {
        lock (this)
        {
            documentQueue.Enqueue(doc);
        }
    }

    public bool IsDocumentAvilable
    {
        get { return documentQueue.Count > 0; }
    }
}

默认值

null不能赋值给泛型类型。原因是 泛型类型也可以实例化为值类型,而null只能用于引用类型。

通过 default 将 null 赋值引用类型。

public T GetDocument()
{
    T doc = default(T);
    lock (this)
    {
        doc = documentQueue.Dequeue();
    }
    return doc;
}

default关键字根据上下文有多种含义。 在switch表示默认值。在泛型中,用于泛型初始化 引用类型 赋值 null,值类型赋值0。

约束

public interface IDocument
{
    string Title { get; set; }
    string Content { get; set; }
}

public class Document : IDocument
{
    public Document()
    {
        
    }

    public Document(string title, string content)
    {
        this.Title = title;
        this.Content = content;
    }

    public string Title { get; set; }
    public string Content { get; set; }
}

class DocumentManage<TDocument> where TDocument: IDocument
{
    private readonly Queue<TDocument> documentQueue = new Queue<TDocument>();

    public void AddDocument(TDocument doc)
    {
        lock (this)
        {
            documentQueue.Enqueue(doc);
        }
    }

    public bool IsDocumentAvilable
    {
        get { return documentQueue.Count > 0; }
    }

    public TDocument GetDocument()
    {
        TDocument doc = default(TDocument);
        lock (this)
        {
            doc = documentQueue.Dequeue();
        }
        return doc;
    }

    public void DisplayAllDocuments()
    {
        foreach (TDocument doc in documentQueue)
        {
            Console.WriteLine(doc.Title);
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        DocumentManage<Document> dm = new DocumentManage<Document>();
        dm.AddDocument(new Document("Ttile A", "Content A"));
        dm.AddDocument(new Document("Ttile B", "Content B"));

        dm.DisplayAllDocuments();

        while (dm.IsDocumentAvilable)
        {
            Document d = dm.GetDocument();
            Console.WriteLine(d.Content);
        }
    }
}

约束 TDocument 必须 实现 IDocment

 where TDocument: IDocument

泛型其他的几种约束类型

value = where T:struct      对结构约束,类型T必须是值类型
where T:class               约束,类型T必须是引用类型
where T:IFoo                约束,类型T必须实现IFoo
where T:Foo                 约束,类型T必须派生自基类IFoo
where T:new()               约束,类型T必须具有无参的构造函数
where T1:T2                 约束,类型T1派生自泛型类型T2,称为裸类型约束

 

继承

实现泛型接口

public class LinkedList<T> : IEnumerable<T>

泛型派生泛型基类

public class Base<T>
{
    
}

public class Derived<T> : Base<T>
{
    
}

指定基类类型

public class Derived<T> : Base<string>
{

}
public abstract class Calc<T>
{
    public abstract T Add(T x, T y);
    public abstract T Sub(T x, T y);
}

public class IntCalc : Calc<int>
{
    public override int Add(int x, int y)
    {
        return x + y;
    }

    public override int Sub(int x, int y)
    {
        return x - y;
    }
}

静态成员

泛型类的静态成员,只能在类的静态成员类访问。

public class StaticDemo<T>
{
    public static int x;
}

StaticDemo<string>.x = 10;
StaticDemo<int>.x = 4;
Console.WriteLine(StaticDemo<string>.x + "      " + StaticDemo<int>.x);

泛型接口

使用泛型可以定义接口,在接口中定义的方法可以带泛型参数。

public interface IComparable<in T>
{
    int CompareTo(T other);
}

public class Person : IComparable<Person>
{
    private string LastName;

    public int CompareTo(Person other)
    {
        return this.LastName.CompareTo(other.LastName);
    }
}

协变和抗变

泛型接口是不变的。通过协变和抗变为泛型接口和泛型委托添加了一个重要的扩展。协变和抗变指对参数和返回值的类型进行转换。

Rectangle 派生自 Shape

public class Shape
{
    public double Width { get; set; }
    public double Height { get; set; }

    public override string ToString()
    {
        return String.Format("Width: {0}, Height: {1}", Width, Height);
    }
}

public class Rectangle : Shape
{
    
}

参数类型协变

public void Display(Shape o)
{
    
}

Rectangle r = new Rectangle{Width = 5, Height = 3};
Display(r);

泛型接口的协变

out关键字标注,泛型接口是协变,意味着返回类型只能是T。

接口IIndex 与 类型 T 是协变,并从制度索引器返回这个类型。

public interface IIndex<out T>
{
    T this[int index] { get; }
    int Count { get;  }
}

实现接口

public class RectangleCollection : IIndex<Rectangle>
{
    private Rectangle[] data = new Rectangle[3] 
    {
        new Rectangle { Height=2, Width=5 },
        new Rectangle { Height=3, Width=7},
        new Rectangle { Height=4.5, Width=2.9}
    };

    private static RectangleCollection coll;
    public static RectangleCollection GetRectangles()
    {
        return coll ?? (coll = new RectangleCollection());
    }

    public Rectangle this[int index]
    {
        get
        {
            if (index < 0 || index > data.Length)
                throw new ArgumentOutOfRangeException("index");
            return data[index];
        }
    }
    public int Count
    {
        get
        {
            return data.Length;
        }
    }
}

coll ?? (coll = new RectangleCollection());

?? 合并运算符,如果 coll 为 null,将调用运算符的右侧。

static void Main(string[] args)
{
    IIndex<Rectangle> rectangles = RectangleCollection.GetRectangles();
    IIndex<Shape> shapes = rectangles;

    for (int i = 0; i < shapes.Count; i++)
    {
        Console.WriteLine(shapes[i]);
    }
}

泛型接口抗变

in 关键标注 泛型接口是抗变的

public interface IDisplay<in T>
{
    void Show(T item); 
}

使用Shape对象作为参数

public class ShapeDisplay : IDisplay<Shape>
{
    public void Show(Shape s)
    {
        Console.WriteLine("{0} Width: {1}, Height: {2}", s.GetType().Name, s.Width, s.Height);
    }
}

 

IDisplay<Shape> shapeDisplay = new ShapeDisplay();
IDisplay<Rectangle> rectangleDisplay = shapeDisplay;
rectangleDisplay.Show(rectangles[0]);

 

在.NET中 参数类型是协变,返回值是抗变。

http://www.cnblogs.com/qionghua/archive/2012/08/02/2620486.html

泛型结构

public struct Nullable<T> where T:struct 
{
    public Nullable(T value)
    {
        this.hasValue = true;
        this.value = value;
    }

    private bool hasValue;

    public bool HasValue
    {
        get { return hasValue; }
    }

    private T value;

    public T Value
    {
        get
        {
            if (!hasValue)
            {
                throw new InvalidOperationException("no value");
            }
            return value;
        }
    }

    public static explicit operator T(Nullable<T> value)
    {
        return value.Value;
    }

    public static implicit operator Nullable<T>(T value)
    {
        return new Nullable<T>(value);
    }

    public override string ToString()
    {
        if(!HasValue)
            return String.Empty;
        return this.value.ToString();
    }
}

 

Nullable<int> x;
x = 4;
x += 3;
if (x.HasValue)
{
    int y = x.Value;
}
x = null;

定义空类型值变量 使用 "?" 运算符

int? v2 = null;
if (v2 == null)
{
    Console.WriteLine("x is null");
}

 

 static int? GetNullableType()
 {
     return null;
 }

 static void Main(string[] args)
 {
     int? x1 = GetNullableType();
     int? x2 = GetNullableType();
     int? x3 = x1 + x2;
     if (x3 == null)
     {
         Console.WriteLine("x3 is null");
     }
 }

类型转换

int y1 = 4;
int? x1 = y1;

// error 不能将null赋值给,非可空类型
x1 = null;
y1 = (int) x1;

// 可以用合并运算符 提供默认值
y1 = x1 ?? 0;

泛型方法

static void Swap<T>(ref T x, ref T y)
{
    T temp;
    temp = x;
    x = y;
    y = temp;
}

static void Main(string[] args)
{
    int i = 4;
    int j = 5;
    Swap<int>(ref j, ref i);
    Console.WriteLine("i={0},j={1}",i,j);
}

 

public class Account
{
    public string Name { get; set; }
    public decimal Balance { get; private set; }

    public Account(string name, Decimal balance)
    {
        this.Name = name;
        this.Balance = balance;
    }
}

static void Main(string[] args)
{
   List<Account> accounts = new List<Account>()
   {
       new Account("xxxx1",1500),
       new Account("xxxx2",2500),
       new Account("xxxx3",3500),
       new Account("xxxx4",4500)
   };

    decimal sum = AccumulateSimple(accounts);
    Console.WriteLine("sum={0}",sum);
}

public static decimal AccumulateSimple(IEnumerable<Account> source)
{
    decimal sum = 0;
    foreach (Account account in source)
    {
        sum += account.Balance;
    }
    return sum;
}

IEnumerable 接口迭代集合元素。

约束的泛型方法

public class Account: IAccount
{
    public string Name { get; set; }
    public decimal Balance { get; private set; }

    public Account(string name, Decimal balance)
    {
        this.Name = name;
        this.Balance = balance;
    }
}

public interface IAccount
{
    decimal Balance { get;  }
    string Name { get;  }
}


 public static decimal AccumulateSimple<TAccount>(IEnumerable<TAccount> source) where TAccount:IAccount
 {
     decimal sum = 0;
     foreach (TAccount account in source)
     {
         sum += account.Balance;
     }
     return sum;
 }

 List<Account> accounts = new List<Account>()
 {
     new Account("xxxx1",1500),
     new Account("xxxx2",2500),
     new Account("xxxx3",3500),
     new Account("xxxx4",4500)
 };

  decimal sum = AccumulateSimple(accounts);
  Console.WriteLine("sum={0}",sum);

委托的泛型方法

 public static T2 AccumulateSimple<T1, T2>(IEnumerable<T1> source,Func<T1,T2,T2> action)
 {
     T2 sum = default(T2);
     foreach (T1 item in source)
     {
         sum = action(item, sum);
     }
     return sum;
 }


 decimal total = AccumulateSimple<Account,decimal>(accounts,(item,sum) => sum += item.Balance);
 Console.WriteLine("sum={0}", total);

Lambda表达式 (item,sum) => sum += item.Balance

posted @ 2016-08-16 18:01  笨重的石头  阅读(346)  评论(0编辑  收藏  举报