zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Codeforces 1485C Floor and Mod (枚举)
    CodeForces 1195D Submarine in the Rybinsk Sea (算贡献)
    CodeForces 1195C Basketball Exercise (线性DP)
    2021年初寒假训练第24场 B. 庆功会(搜索)
    任务分配(dp)
    开发工具的异常现象
    Telink MESH SDK 如何使用PWM
    Telink BLE MESH PWM波的小结
    [LeetCode] 1586. Binary Search Tree Iterator II
    [LeetCode] 1288. Remove Covered Intervals
  • 原文地址:https://www.cnblogs.com/z888/p/5777337.html
Copyright © 2011-2022 走看看