ToCharArray和ToArray的区别
什么是 ToCharArray
和的ToArray
string mystring = "abcdef";
char[] items1 = mystring.ToCharArray();
char[] items2 = mystring.ToArray();
的结果似乎是相同的。
The result seems to be the same.
string.ToCharArray()
是String类的成员。
string.ToCharArray()
is a member of the string class.
string.ToArray ()
实际使用一个 ToArray的()
扩展的IEnumerable<的; T>
,采取的事实,即字符串
工具的IEnumerable<焦炭方式>
string.ToArray()
is actually using a ToArray()
extension of IEnumerable<T>
, taking advantage of the fact that string
implements IEnumerable<char>
.
在这两个, string.ToCharArray()
很可能是更好的性能。
Of the two, string.ToCharArray()
is likely to be more performant.
从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;
}
}
正如你所看到的,这是一个复杂得多!
As you can see, that's a LOT more complicated!
为什么不的IEnumerable< T> .ToArray()
使用优化的路径
Why doesn't IEnumerable<T>.ToArray()
use the optimised path?
有是我们需要解释一件事。
There's one other thing we need to explain.
如果您检查的实施缓冲器< T>
你会看到这样的优化:
If you inspect the implementation of Buffer<T>
you'll see this optimisation:
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()
。
You could reasonably ask why that path isn't taken? If it was, this would be a good optimisation for string.ToArray()
.
那么,答案是一个很好的优化简单地说:A 字符串
不执行的ICollection< T>
,因此源作为的ICollection< TElement方式>
将返回null,并且优化将无法完成
Well, the answer is simply: A string
doesn't implement ICollection<T>
and therefore source as ICollection<TElement>
will return null, and that optimisation will not be done.
更糟糕的是,通过非优化的路径缓冲器< T>
将使用字符串
枚举,其实现如下:
Even worse, the non-optimised path through Buffer<T>
will use the string
enumerator, which is implemented as follows:
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);
}
}
这引入了低效率的完全是另外一个层次。
This introduces a whole other level of inefficiency.
这个故事的寓意
不要使用的IEnumerable<焦炭> .ToArray()
而不是 string.ToCharArray()