• 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

  • 相关阅读:
    介绍Collection框架的结构;Collection 和 Collections的区别
    Mybites和hibernate的优缺点和区别2
    Mybites和hibernate的优缺点和区别
    AJAX如何获取从前台传递过来的数据然后在通过servle传递给后台
    list map set 集合的区别
    乐观锁和悲观锁的区别
    python生产消费Kafka
    python类型转换
    python实现远程方法调用
    Scala常用数据结构
  • 原文地址:https://www.cnblogs.com/z888/p/5777337.html
Copyright © 2020-2023  润新知