Slice2CS编译器支持两种不同的sequences映射,默认情况下,sequence被映射成c#数组;同样我们也可以利用元指令强制编译器将sequence映射为强类型集合(CollectionBase),即让它继承自System.Collections.CollectionBase接口。
1 序列映射为数组
默认情况下,sequence被映射成c# 数组类型,这意味着,Slice2CS编译器只是将SliceSequece生成为一个指定类型的数组,而不会生成任何其它的代码。例如:
sequence<Fruit> FruitPlatter;
上面的定义将会生成下面两个代码中的任一一个::
Fruit[] fp = { Fruit.Apple, Fruit.Orange };
或
Fruit fp[] = new Fruit[2];
fp[0] = Fruit.Apple;
fp[1] = Fruit.Orange;
将sequence映射成数组是简单而又高效的,特别是当sequence只包含值类型时,因为访问数组的元素不需要装箱和拆箱操作。
2 序列映射为CollectionBase
将sequence映射为数组是很简单的,但如果sequence的元素是不固定的,而我们又将其映射为数组,我们就不能进行动态的增加、删除序列的元素。这种情况下,我们可以利用元指令强制编译器将序列映射为CollectionBase:
["clr:collection"] sequence<Fruit> FruitPlatter;
上面的定义产生的代码如下:
using System;
using System.Collections;
public class FruitPlatter : CollectionBase,ICloneable
{
public FruitPlatter();
public FruitPlatter(int capacity);
public FruitPlatter(Fruit[] a);
public Fruit this[int index]
{
get;set;
}
public virtual int Capacity
{
get;set;
}
#region ICloneable Members
public object Clone();
#endregion
public void CopyTo(Fruit[] a);
public void CopyTo(Fruit[] a, int i);
public void CopyTo(int i, Fruit[] a, int ai, int c);
public Fruit[] ToArray();
public void AddRange(FruitPlatter s);
public void AddRange(Fruit[] a);
public int Add(Fruit value);
public int IndexOf(Fruit value);
public void Insert(int index, Fruit value);
public void Remove(Fruit value);
public bool Contains(Fruit value);
public virtual void TrimToSize();
public virtual void Sort()
public virtual void Sort(IComparer comparer)
public virtual void Sort(int index, int count,IComparer comparer)
public virtual void Reverse()
public virtual void Reverse(int index, int count)
public virtual int BinarySearch(Fruit value)
public virtual int BinarySearch(Fruit value, System.Collections .IComparer comparer)
public virtual int BinarySearch(int index, int count,Fruit value,IComparer comparer)
public virtual void InsertRange(int index, FruitPlatter c)
public virtual void InsertRange(int index, Fruit[] c)
public virtual void RemoveRange(int index, int count)
public virtual FruitPlatter GetRange(int index, int count)
public virtual void SetRange(int index, FruitPlatter c)
public virtual void SetRange(int index, Fruit[] c)
public virtual int LastIndexOf(Fruit value)
public virtual int LastIndexOf(Fruit value, int startIndex)
public virtual int LastIndexOf(Fruit value, int startIndex, in t count)
public static FruitPlatter Repeat(Fruit value, int count)
public override int GetHashCode();
public override bool Equals(object other);
public static bool Equals(FruitPlatter lhs,FruitPlatter rhs);
public static bool operator ==(FruitPlatter lhs,FruitPlatter rhs);
public static bool operator !=(FruitPlatter lhs,FruitPlatter rhs);
// ...
}
生成的类提供了索引器、Add,IndexOf, Insert,Remove,Contains方法的实现。为了便于使用,生成的类又新增了一些方法,具体每个方法的功能一般都可以见名知义,这里就不介绍了。
3 该选择择那种类型的序列映射
注意你只能在序列的定义的起始处决定将序列映射为数组还是映射为CollectionBase。一旦你决定了,你就不能在序列定义的其它地方改变它。
将序列映射为CollectionBase是很方便,但同时,它也是比较低效的。值类型的序列如果将它映射为CollectionBase,那么由于对它的Insert、Remove操作是比较低效的(因为存在装箱、折箱操作),这种情况下,将序列映射为数组是一种比较好的选择。
通常,如果序列的个数在其生命周期中有变化的话就将其映射为CollectionBase;如果序列符合下列情况,就将其映射为数组:
1 序列的个数在其生命周期中不会变化
2 序列要用到性能优先的环境中。
在实践中,如果序列的元素是值类型的,将其映射为数组是比较高效的。例如:如果你用sequence<byte>来缓存要发送的字节数据,这时将序列映射为数组是比较快的。
4 多维序列的映射
Slice允许你定义序列的序列:
enum Fruit { Apple, Orange, Pear };
["clr:collection"] sequence<Fruit> FruitPlatter;
["clr:collection"] sequence<FruitPlatter> Cornucopia;
按照上面的定义,生成的Cornucopia序列的代码大致如下(为了说明目的,只选取了一部分):
public class Cornucopia : System.Collections.CollectionBase,
System.ICloneable
{
public FruitPlatter this[int index] { get; set; }
public int Add(FruitPlatter value);
public int IndexOf(FruitPlatter value);
public void Insert(int index, FruitPlatter value);
public void Remove(FruitPlatter value);
public bool Contains(FruitPlatter value);
// ...
}
现在我们修改上面的定义:
enum Fruit { Apple, Orange, Pear };
sequence<Fruit> FruitPlatter;
["clr:collection"] sequence<FruitPlatter> Cornucopia;
那么生成的样式就变为了如下的样式(同样,为了清晰,进行了节选)
public class Cornucopia : System.Collections.CollectionBase,
System.ICloneable
{
public Fruit[] this[int index] { get; set; }
public int Add(Fruit[] value);
public int IndexOf(Fruit[] value);
public void Insert(int index, Fruit[] value);
public void Remove(Fruit[] value);
public bool Contains(Fruit[] value);
// ...
}
就像你所看到的,上面的代码中已经没有了FruitPlatter类型,取而代之的是Fruit数组。
当然,我们可以更改元指令,将Cornucopia序列映射为数组,而将FruitPlatter映射为CollectionBase。在这种情况下,编译器不为会Cornucopia生成任何代码,而只是简单的将Cornucopia当成了FruitPlatter的数组。