String
类代表“字符的集合”并且是不可变的。它的索引器只定义了 get 函数,这没关系,因为Char
“struct”也是不可变的。所有String
用于操作的方法都返回String
类的新实例。
我最近需要一个不可变的通用集合,它与(我们称之为)完全一样。String
Foo<T>
- 它应该是通用的(尽管我只会将它与结构一起使用)。
- 它应该是不可变的。
- 它应该具有用于项目序列的方法,例如:
IndexOf(Foo<T>)
或者IndexOf(IEnumerable<T>)
StartsWith(Foo<T>)
或者StartsWith(IEnumerable<T>)
EndsWith(Foo<T>)
或者EndsWith(IEnumerable<T>)
Take(int, int)
(带有起始索引和长度,就像Substring
)Contains(Foo<T>)
或者Contains(IEnumerable<T>)
LastIndexOf(Foo<T>)
或者LastIndexOf(IEnumerable<T>)
- 等等
我创建了一个不可变类,用于对其项目的只读访问,并编写了一些扩展方法来模仿 String 的功能,但我真的怀疑我的实现效率(我实际上要求Replace
方法,here)。我对替代品很好奇。因为String
做了我需要的一切(不幸的是,只有字符),所以感觉就像重新发明了轮子。
我需要的最简单的定义是“通用字符串”。
- .NET 中有类似的东西还是为.NET 编写的?
- 如果没有,一些创建指南会很棒。
回答和评论后编辑:
我需要的不是包装指定的底层可变集合并将其表示为只读的包装器。我需要的是一个真正不可变的T
with 方法集合来处理T
. IList<T>.IndexOf(T)
例如,它获取item的索引。现在想想String.IndexOf(String)
方法,它(不像 的IndexOf(Char)
方法String
)获取一个字符序列String
的索引并且有很多这样的方法。
现在,为什么我不使用ReadOnlyCollection<T>
:除了它不支持“ (String-like) 方法,例如 Contains(IEnumerable) ”之外,它也不是不可变的。一个例子:
var array = new char[] { 'a', 'b', 'c', 'd', 'e' };
var str = new string(array);
// array[2] is 'c' and str[2] is also 'c'
// I can't do str[2] = 'f', but:
array[2] = 'f';
// Now, array[2] is 'f' but str[2] is still 'c'
没有办法(这不是黑客)来改变字符串的状态。现在,让我们来看看ReadOnlyCollection<T>
:
var array = new int[] { 1, 2, 3, 4, 5 };
var col = new ReadOnlyCollection<int>(array);
// Here the col[2] is 3
// I can't do col[2] = 6, but:
array[2] = 6;
// Now the col[2] is 6 as well.
根据要求进行编辑 - 我目前使用的是:
集合(Foo<T>
):
// Something I started like an hour ago. The only thing it does right now is to
// copy (not wrap) a specified enumerable and provide read-only access to it.
public sealed class Foo<T> : IList<T> where T: struct
{
private readonly T[] _Array;
public T this[int index] { get { return _Array[index]; } }
IList<T>.this[int index]
{
get { return this[index]; }
set { throw new NotSupportedException(); }
}
public Foo(IEnumerable<T> collection)
{
// Enumerable.ToArray() method copies the content of the specified array.
// Whetever happens to the "collection", value of "_Array" will stay the same.
_Array = collection.ToArray();
}
// Most of the methods of IList<T> are explicitly implemented. IsReadOnly
// returns true and the methods that cause a change in collection throw
// "NotSupportedException"s just like ReadOnlyCollection<T>.
// IEnumerable<T> implementation uses an iterator block.
}
扩展方法:
// Extensions I used to manipulate collections so far.
// These are the things I want to get rid of.
public static class FooHelpers
{
// I remove the bodies of these methods due to the confusion they have caused.
// How they work is irrelevant and I posted these because of a request.
public static bool Contains<T>(this IEnumerable<T> collection,
IList<T> pattern) { }
public static int IndexOf<T>(this IEnumerable<T> collection,
IList<T> pattern) { }
public static int LastIndexOf<T>(this IList<T> collection,
IList<T> pattern) { }
public static IEnumerable<int> IndicesOf<T>(this IEnumerable<T> collection,
IList<T> pattern) { }
public static IEnumerable<int> LastIndicesOf<T>(this IList<T> collection,
IList<T> pattern) { }
public static IEnumerable<T[]> Split(this IList<T> source,
IList<T> seperator) { }
public static bool StartsWith<T>(this IEnumerable<T> collection,
IList<T> pattern) { }
public static bool EndsWith<T>(this IList<T> collection,
IList<T> pattern) { }
public static IEnumerable<T> Take<T>(this IList<T> collection,
int startIndex,
int length) { }
public static IEnumerable<T> Take<T>(this IEnumerable<T> collection,
int startIndex,
int length) { }
public static IEnumerable<T> TakeAll<T>(this IList<T> collection,
int startIndex) { }
}