ToCharArray
和 ToArray
有什么区别?
string mystring = "abcdef";
char[] items1 = mystring.ToCharArray();
char[] items2 = mystring.ToArray();
结果似乎是一样的。
ToCharArray
和 ToArray
有什么区别?
string mystring = "abcdef";
char[] items1 = mystring.ToCharArray();
char[] items2 = mystring.ToArray();
结果似乎是一样的。
string.ToCharArray()
是字符串类的一个成员方法。
string.ToArray()
实际上使用了 IEnumerable<T>.ToArray()
扩展方法,利用了 string
实现了 IEnumerable<char>
接口的特性。
在这两者之间,string.ToCharArray()
可能会更具有性能优势。
从 C# 参考源代码中看到,string.ToCharArray()
的实现是:
unsafe public char[] ToCharArray() {
// <
int length = Length;
char[] chars = new char[length];
if (length > 0)
{
fixed (char* src = &this.m_firstChar)
fixed (char* dest = chars) {
wstrcpy(dest, src, length);
}
}
return chars;
}
还从C#参考源代码中得知,IEnumerable<T>.ToArray()
的实现如下:
public static TSource[] ToArray<TSource>(this IEnumerable<TSource> source) {
if (source == null) throw Error.ArgumentNull("source");
return new Buffer<TSource>(source).ToArray();
}
...
struct Buffer<TElement>
{
internal TElement[] items;
internal int count;
internal Buffer(IEnumerable<TElement> source) {
TElement[] items = null;
int count = 0;
ICollection<TElement> collection = source as ICollection<TElement>;
if (collection != null) {
count = collection.Count;
if (count > 0) {
items = new TElement[count];
collection.CopyTo(items, 0);
}
}
else {
foreach (TElement item in source) {
if (items == null) {
items = new TElement[4];
}
else if (items.Length == count) {
TElement[] newItems = new TElement[checked(count * 2)];
Array.Copy(items, 0, newItems, 0, count);
items = newItems;
}
items[count] = item;
count++;
}
}
this.items = items;
this.count = count;
}
internal TElement[] ToArray() {
if (count == 0) return new TElement[0];
if (items.Length == count) return items;
TElement[] result = new TElement[count];
Array.Copy(items, 0, result, 0, count);
return result;
}
}
正如您所看到的,这更加复杂了!
IEnumerable<T>.ToArray()
为什么不使用优化路径?
还有一件事情需要解释。
如果您检查Buffer<T>
的实现,您会看到这个优化:
ICollection<TElement> collection = source as ICollection<TElement>;
if (collection != null) {
count = collection.Count;
if (count > 0) {
items = new TElement[count];
collection.CopyTo(items, 0);
}
}
为什么不采用这种方法呢?这样做可以对 string.ToArray()
进行优化。
答案很简单:一个 string
没有实现 ICollection<T>
,因此source as ICollection<TElement>
将返回 null,并且该优化将无法进行。
Buffer<T>
的未经过优化的路径将使用 string
枚举器,其实现如下:public sealed class CharEnumerator : IEnumerator, ICloneable, IEnumerator<char>, IDisposable
{
private String str;
private int index;
private char currentElement;
internal CharEnumerator(String str) {
Contract.Requires(str != null);
this.str = str;
this.index = -1;
}
public Object Clone() {
return MemberwiseClone();
}
public bool MoveNext() {
if (index < (str.Length-1)) {
index++;
currentElement = str[index];
return true;
}
else
index = str.Length;
return false;
}
public void Dispose() {
if (str != null)
index = str.Length;
str = null;
}
/// <internalonly/>
Object IEnumerator.Current {
get {
if (index == -1)
throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumNotStarted));
if (index >= str.Length)
throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumEnded));
return currentElement;
}
}
public char Current {
get {
if (index == -1)
throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumNotStarted));
if (index >= str.Length)
throw new InvalidOperationException(Environment.GetResourceString(ResId.InvalidOperation_EnumEnded));
return currentElement;
}
}
public void Reset() {
currentElement = (char)0;
index = -1;
}
}
ICollection<TElement> collection = source as ICollection<TElement>;
if (collection != null) {
count = collection.Count;
if (count > 0) {
items = new TElement[count];
collection.CopyTo(items, 0);
}
}
这引入了另一个层次的低效。
故事的寓意
永远不要使用 IEnumerable<char>.ToArray()
而不是 string.ToCharArray()
!
ToArray()
不够高效,那将更具教育意义:因为string
没有实现ICollection<char>
,这意味着ToArray()
无法提前知道长度,从而会创建许多中间缓冲区。(否则,人们可以合理地认为LINQ足够“聪明”,选择快速路径。) - Theodoros ChatzigiannakisToCharArray
方法中 // <
的目的是什么? - corsiKaToCharArray
方法可将字符串中的字符提取到一个字符数组中。然后显示原始字符串和数组中的元素。
using System;
public class Example
{
public static void Main()
{
String s = "AaBbCcDd";
var chars = s.ToCharArray();
Console.WriteLine("Original string: {0}", s);
Console.WriteLine("Character array:");
for (int ctr = 0; ctr < chars.Length; ctr++)
Console.WriteLine(" {0}: {1}", ctr, chars[ctr]);
}
}
ToArray方法是作用于范围的List类的一个方法。
using System;
using System.Collections.Generic;
public class Example
{
public static void Main()
{
string[] input = { "Brachiosaurus",
"Amargasaurus",
"Mamenchisaurus" };
List<string> dinosaurs = new List<string>(input);
Console.WriteLine("\nCapacity: {0}", dinosaurs.Capacity);
Console.WriteLine();
foreach( string dinosaur in dinosaurs )
{
Console.WriteLine(dinosaur);
}
Console.WriteLine("\nAddRange(dinosaurs)");
dinosaurs.AddRange(dinosaurs);
Console.WriteLine();
foreach( string dinosaur in dinosaurs )
{
Console.WriteLine(dinosaur);
}
Console.WriteLine("\nRemoveRange(2, 2)");
dinosaurs.RemoveRange(2, 2);
Console.WriteLine();
foreach( string dinosaur in dinosaurs )
{
Console.WriteLine(dinosaur);
}
input = new string[] { "Tyrannosaurus",
"Deinonychus",
"Velociraptor"};
Console.WriteLine("\nInsertRange(3, input)");
dinosaurs.InsertRange(3, input);
Console.WriteLine();
foreach( string dinosaur in dinosaurs )
{
Console.WriteLine(dinosaur);
}
Console.WriteLine("\noutput = dinosaurs.GetRange(2, 3).ToArray()");
string[] output = dinosaurs.GetRange(2, 3).ToArray();
Console.WriteLine();
foreach( string dinosaur in output )
{
Console.WriteLine(dinosaur);
}
}
}
如果我们谈论将字符串转换为字母,ToCharArray()函数比ToArray()更快。