.NET中是否有通用的BitArray?我只发现了非通用的那个。
可以有一个通用的BitArray吗? (即它是否合理?)
也许我应该说类型安全不通用。
基本上,当您将类型枚举为object
时,它应该不是int
还是bool
?或者其中一个在另一个成员普查员中提供?
foreach (bool bit in myBitArray)
{
}
我刚检查了BitArray
类的枚举器,但除了object
属性外,所有内容都返回.Current
:
public virtual object Current
答案 0 :(得分:9)
BitArray是NET 1.x时代的专业集合类。只要您使用ba.Set(int, bool)
和索引器属性,它就是类型安全的。
什么是'not typesafe'是枚举,BitArray实现IEnumerable而不是IEnumerable<布尔取代。所以Joan是对的,使用foreach()
涉及从对象转换为bool。
但这是一个真正的问题吗? BitArray中的元素是布尔值,只有与它们的位置结合才有意义。请注意,BitArray没有Add()
方法,只有Set(i, true)
。
所以简单的答案是:不要使用foreach()
或基于IEnumerable的任何其他内容。它只产生一个很难用的真/假值流。
在下面的代码片段中,BitArray是完全类型安全且高效的:
BitArray isEven = ...;
for(int i = 0; i < isEven.Count; i++)
{
isEven.Set(i, i % 2 == 0);
}
答案 1 :(得分:8)
不,没有。
我甚至不确定BitArray中哪一部分是通用的。
使用BitArray
创建一个扩展方法来获取bool[]
并返回 List<bool>
或for
并不难循环BitArray
。 for
循环不会涉及拳击,因为您将使用BitArray
的索引器,而 bool[]
List<bool>
可以在没有装箱的情况下进行枚举同样。
示例扩展方法:
static List<bool> ToList( this BitArray ba ) {
List<bool> l = new List<bool>(ba.Count);
for ( int i = 0 ; i < ba.Count ; i++ ) {
l.Add( ba[ i ] );
}
return l;
}
我从快速基准(好奇心克服了我)中发现的是foreach (bool b in myBitArray.ToList())
花费了foreach (bool b in myBitArray)
的75%到85%的时间。这每次创建列表。创建列表一次并迭代多次占用foreach (bool b in myBitArray)
所花费的时间的20%到25%。如果您需要多次迭代bool
值并且知道它们在您调用myBitArray.ToList()
时不会发生更改,则只能利用它。< / p>
foreach (bool b in Enumerable.Cast<bool(myBitArray))
花费了foreach (bool b in myBitArray)
花费的时间的150%。
另一个编辑:我会说,因为它是一款游戏,所以你可以做任何事情来做一个非常精益的迭代,没有装箱/拆箱,甚至如果这意味着自己编写BitArray
。您可以节省时间并使用Reflector来复制大部分学习BitArray
的代码,因为该类是密封的(无法继承和添加功能),以防万一是一个有点擅长的优化来学习。
编辑:了解将代码复制出Reflector的建议。有些东西,如迭代器和闭包,会产生奇怪的生成代码,无论如何都不想直接复制。
答案 2 :(得分:7)
您可以在不装箱的情况下迭代BitArray
或将其转换为List<bool>
:
public static IEnumerable<bool> GetTypeSafeEnumerator(this BitArray ba) {
for (int i = 0; i < ba.Length; i++)
yield return ba[i];
}
这应该比转换到列表更快,并且肯定会减少更少的内存。
当然,它仍然比普通的for
循环慢,如果你真的需要性能,你应该使用
for (int i = 0; i < ba.Length; i++) {
bool b = ba[i];
...
}
使用MiniBench进行基准测试:
public static class Class1 {
private const int N = 10000;
private const int M = 100;
public static void Main() {
var bitArray = new BitArray(N);
var results1 = new TestSuite<BitArray, int>(
"Different looping methods")
.Plus(PlainFor, "Plain for loop")
.Plus(ForEachBool, "foreach(bool bit in bitArray)")
.Plus(CastBool, "foreach(bool bit in bitArray.Cast<bool>)")
.Plus(TypeSafeEnumerator, "foreach(bool bit in bitArray.GetTypeSafeEnumerator())")
.Plus(UseToList, "foreach(bool bit in bitArray.ToList())")
.RunTests(bitArray, 0);
results1.Display(ResultColumns.All, results1.FindBest());
var results2 = new TestSuite<BitArray, int>(
"Avoiding repeated conversions")
.Plus(PlainFor1, "Plain for loop")
.Plus(CastBool1, "foreach(bool bit in bitArray.Cast<bool>)")
.Plus(TypeSafeEnumerator1, "foreach(bool bit in bitArray.GetTypeSafeEnumerator())")
.Plus(UseToList1, "foreach(bool bit in bitArray.ToList())")
.RunTests(bitArray, 0);
results2.Display(ResultColumns.All, results2.FindBest());
}
private static int PlainFor1(BitArray arg) {
int j = 0;
for (int k = 0; k < M; k++) {
for (int i = 0; i < arg.Length; i++) {
j += arg[i] ? 1 : 0;
}
}
return j;
}
private static int CastBool1(BitArray arg) {
int j = 0;
var ba = arg.Cast<bool>();
for (int k = 0; k < M; k++) {
foreach (bool b in ba) {
j += b ? 1 : 0;
}
}
return j;
}
private static int TypeSafeEnumerator1(BitArray arg) {
int j = 0;
var ba = arg.GetTypeSafeEnumerator();
for (int k = 0; k < M; k++) {
foreach (bool b in ba) {
j += b ? 1 : 0;
}
}
return j;
}
private static int UseToList1(BitArray arg) {
int j = 0;
var ba = arg.ToList();
for (int k = 0; k < M; k++) {
foreach (bool b in ba) {
j += b ? 1 : 0;
}
}
return j;
}
private static int PlainFor(BitArray arg) {
int j = 0;
for (int i = 0; i < arg.Length; i++) {
j += arg[i] ? 1 : 0;
}
return j;
}
private static int ForEachBool(BitArray arg) {
int j = 0;
foreach (bool b in arg) {
j += b ? 1 : 0;
}
return j;
}
private static int CastBool(BitArray arg) {
int j = 0;
foreach (bool b in arg.Cast<bool>()) {
j += b ? 1 : 0;
}
return j;
}
private static int TypeSafeEnumerator(BitArray arg) {
int j = 0;
foreach (bool b in arg.GetTypeSafeEnumerator()) {
j += b ? 1 : 0;
}
return j;
}
private static int UseToList(BitArray arg) {
int j = 0;
foreach (bool b in arg.ToList()) {
j += b ? 1 : 0;
}
return j;
}
public static List<bool> ToList(this BitArray ba) {
List<bool> l = new List<bool>(ba.Count);
for (int i = 0; i < ba.Count; i++) {
l.Add(ba[i]);
}
return l;
}
public static IEnumerable<bool> GetTypeSafeEnumerator(this BitArray ba) {
for (int i = 0; i < ba.Length; i++)
yield return ba[i];
}
}
结果(姓名,迭代次数,总持续时间,得分(高分为差)):</ p>
============ Different looping methods ============
Plain for loop 456899 0:28.087 1,00
foreach(bool bit in bitArray) 135799 0:29.188 3,50
foreach(bool bit in bitArray.Cast<bool>) 81948 0:33.183 6,59
foreach(bool bit in bitArray.GetTypeSafeEnumerator()) 179956 0:27.508 2,49
foreach(bool bit in bitArray.ToList()) 161883 0:27.793 2,79
============ Avoiding repeated conversions ============
Plain for loop 5381 0:33.247 1,00
foreach(bool bit in bitArray.Cast<bool>) 745 0:28.273 6,14
foreach(bool bit in bitArray.GetTypeSafeEnumerator()) 2304 0:27.457 1,93
foreach(bool bit in bitArray.ToList()) 4603 0:30.583 1,08
答案 3 :(得分:2)
如果它存在,您将传递给BitArray<T>
的泛型类型参数的示例是什么?
BitArray
定义为:
管理一个紧凑的位值数组, 代表布尔人, 其中true表示该位是 on(1)和false表示该位 关(0)。
这种类型是一个优化的位数组,没有别的。将它设为通用没有任何价值,因为no members可以从类型中分解出来。像这样的任何专门的集合可以作为一些父通用集合的封闭构造类型。换句话说,BitArray
有点像List<Boolean>
(当然会添加许多有用的方法)。
修改:是的,此类型实现IEnumerable
并且未实现IEnumerable<T>
- 这很可能是因为它是旧类型并且未更新。请记住,您可以使用Enumerable.Cast<TResult>
解决此问题:
yourBitArray.Cast<bool>();
答案 4 :(得分:2)
您对通用版本有什么可能的原因? BitArray可能在比特旁边使用什么类型,或者根据情况变成比特的布尔值?
更新:
它是类型安全的。如果你正在做一个foreach(bitArray中的var位),那么bit将作为一个对象出现,但你可以像foreach一样轻松(bitArray中的bool位),这对于实现IEnumerable而不是IEnumerable<T>.
的所有集合都会发生。