3-C# 泛型(随笔)

3-C# 泛型(随笔)

    • 1. 泛型概述
      • 1.1 性能
      • 1.2 类型安全
      • 1.3 二进制代码的重用
      • 1.4 代码的扩展
      • 1.5 命名约定
    • 2. 创建泛型类
    • 3. 泛型类的功能
      • 3.1 默认值

1. 泛型概述

  有了泛型,就可以创建独立于被包含类型的类和方法了,我们不必给不同的类型编写功能相同的许多方法或类,值创建一个方法或类即可。另一个减少代码的选项是使用Object类,但是其不是类型安全的。泛型类使用泛型类型,并可以根据需要用特定的类型替换泛型类型。这就保证了类型安全性:如果某个类型不支持泛型类,编译器就会出现错误。 下面介绍泛型的优点和缺点,尤其是:
  • 性能
  • 类型安全性
  • 二进制代码重用
  • 代码的扩展
  • 命名约定

1.1 性能

  值类型存储在栈上,引用类型存储在堆上。C#类是引用类型,结构是值类型。.NET很容易把值类型转换为引用类型,所以可以在需要对象(对象是引用类型)的任意地方使用值类型。**从值类型转换为引用类型成为装箱**。如果方法需要把一个对象作为参数,同时传递一个值类型,此时装箱操作会自动进行。另一方面,装箱的值类型可以使用拆箱操作转换为值类型。在拆箱时,需要使用类型强制转换运算符。
System.Collections: ArrayList类

var list = new ArrayList();
list.Add(44); //装箱操作

int i1 = (int)list[0]; //拆箱操作

foreach (int i2 in list)
{
	Console.WriteLine(i2); //拆箱操作
}

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

System.Collections.Generic: List<T>
List<>不使用对象,而是在使用时定义类型,在下面的例子中,List<T>类的泛型类型定义为int,所以int类型在JIT编译器动态生成的类中使用,不再进行装箱和拆箱操作
var list  = new List<int>();
list.Add(44); 

int i1 = list[0];

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

1.2 类型安全

  泛型的另一个特性是类型安全。与ArrayList类一样,如果使用对象,就可以在这个集合中添加任意类型。例如我们在ArrayList的几何中添加一个整数、一个字符串和一个MyClass类。如果使用foreach迭代,编译器会编译这段代码,但是会出现一个运行异常,因为不是所有的元素都可以强制转换为int类型。   错误应尽早发现。在泛型类List中,泛型类型T定义了允许使用的类型。如果添加了其他类型,则编译器不会编译这段代码。

1.3 二进制代码的重用

  泛型允许更好的重用二进制代码。泛型类可以定义一次,并且可以用许多不同的类型实例化。不需要像C++那样访问源代码。
var list = new List<int>();
list.Add(44);

var stringList = new List<string>();
stringList.Add("mystring");

var myClassList = new List<myClass>();
myClassList.Add(new MyClass());
泛型类型可以在一种语言中定义,在任何其他.NET语言中使用。   

1.4 代码的扩展

1. 因为泛型类的定义会放在程序集中,所以用特定类型实例化泛型类不会在IL代码中复制这些类 2. JIT编译器把泛型类编译为本地代码时,会给每个值创建一个新类。因为值类型包含在实例化的泛型类的内存中,同时因为每个值类型对内存的要求都不同,所以要为每个值类型实例化一个新类 3 引用类型共享同一个本地类的所有相同的实现代码。这是因为引用类型在实例化的泛型类中只需要4个字节的内存地址(32位系统)

1.5 命名约定

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

public delegate TOutput Converter<TInput, TOutput>(TInput from);

public class SortedList<TKey, TValue>();

2. 创建泛型类

  首先介绍一个一般的、非泛型的简化链表类,它可以包含任意类型的对象,之后再把这个类型转换为泛型类。
    public class LinkNodeList
    {
        /*
         * 链表中,一个元素引用下一个元素
         * Value:初始化构造函数
         * Previous:上一个元素的引用
         * Next:下一个元素的引用
        */
        public LinkNodeList(object value)
        {
            this.Value = value;
        }

        public object Value { get; private set; }

        public LinkNodeList Previous { get; internal set; }
        public LinkNodeList Next { get; internal set; }
    }
    public class LinkedList
    {
        /*
         * LinkeList类包含LinkedNodeList类型的两个属性Last,First;
         * First: 链表的头
         * Last: 链表的尾
         * AddLast(): 在链表尾添加一个新元素
         * GetEnumerator(): 通过其实现foreach遍历
         */

        public LinkNodeList First { get; private set; }
        public LinkNodeList Last { get; private set; }

        public LinkNodeList AddLast(object node)
        {
            var newNode = new LinkNodeList(node);
            if (First == null)
            {
                First = newNode;
                Last = First;
            }
            else
            {
                LinkNodeList previous = Last;
                Last.Next = newNode;
                Last = newNode;
                Last.Previous = previous;

            }
            return newNode;
        }

        public IEnumerator GetEnumerator()
        {
            LinkNodeList current = First;
            while (current != null)
            {
                yield return current.Value;
                current = current.Next;
            }
        }
    }
使用LinkedList的示例:
    class Program
    {
        static void Main(string[] args)
        {
            LinkedList testList = new LinkedList();
            testList.AddLast(1);
            testList.AddLast(2);
            testList.AddLast(3);

            foreach (int i in testList)
            {
                Console.WriteLine(i);
            }

            Console.ReadLine();
        }
    }
  下面创建链表的泛型版本。泛型类的定义与一般类类似,只是要使用泛型类型声明。之后,泛型类型就可以在类中用作一个字段成员,或者方法的参数类型。
public class LinkNodeList<T>
{
	public LinkNodeList(T value)
	{
		this.Value = value;
	}
	
	private T Value {get; private set;}
	private LinkNodeList<T> Next {get; internal set;}
	private LinkNodeList<T> Prev {get; internal set;}
}
   下面的代码将LinkedList类也改为泛型类:
public class LinkedList<T>:IEnumerator<T>
{
	public LinkNodeList<T> First {get; private set;}
	public LinkNodeList<T> Last {get; private set;}
    
    public LinkNodeList<T> AddLast(T node)
    {
    	var newNode = new LinkNodeList<T>(node);
    	if (First == null)
    	{
    		First = newNode;
    		Last = First;
    	}
    	else
    	{
    		LinkNodeList<T> previous = Last;
    		Last.Next = newNode;
    		Last = newNode;
    		Last.Prev = previous;

    	}
		
		public IEnumerator<T> GetEnumerator()
		{
			LinkNedeList<T> current = First;
	
			while (current != null)
			{
				yield return current.Value;
				current = current.Next;
			}
		}
    }
	
}

3. 泛型类的功能

  本节讨论下面四个主题:默认值、约束、继承、静态成员
//泛型文档管理器的示例
  //先创建一个新的控制台项目DocumentManager, 并添加DocumentManager类。AddDocument()方法将一个文档添加到队列中。如果队列不为孔,IsDocumentAvailable只读属性就返回true
using System;
using System.Collections.Generics
{
	namespace Wrox.ProCSharp.Generic
	{
		public class DocumentManager<T>
		{
			private readonly Queue<T> documentQuene = new Queue<T>;
			
			public void AddDocument()
			{
				lock(this)
				{
					documentQueue.Enqueue(doc);
				}
			}
	
			public bool IsDocumentAvailable
			{
				get { return documentQueue.Count > 0; }
			}
		}
	}
}

3.1 默认值

当需要将类型T指定为null时,不能把null赋予泛型类型。原因是泛型类型也可以实例化为值类型,而null只能应用于引用类型。
在CSharp中,可以使用default关键字,将null赋予引用,将0赋予值类型

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

你可能感兴趣的:(C#,and,Halcon,编程语言)