4

.NET 中有通用的 BitArray 吗?我只找到了非通用的。

可以有一个通用的 BitArray 吗?(即合理吗?)


编辑:

也许我应该说类型安全不是通用的。

基本上,当您将类型枚举为 时object,它不应该是intorbool吗?或者其中一个在另一个成员枚举器中提供?


例子:

foreach (bool bit in myBitArray)
{

}

编辑:

我刚刚检查了BitArray类的枚举器,但一切都返回了一个objectexcept.Current属性:

public virtual object Current
4

5 回答 5

9

BitArray 是 NET 1.x 时代的一个专门的集合类。只要您使用ba.Set(int, bool)和 indexer 属性,它就非常安全。

“非类型安全”是枚举,BitArray 实现 IEnumerable 但不是 IEnumerable<bool>。所以琼是对的,使用foreach()涉及从对象转换为布尔值。

但这是一个真正的问题吗?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);
}
于 2009-07-31T20:23:04.733 回答
8

不,没有。

如果有的话,我什至不确定 BitArray 的哪一部分是通用的。

创建一个扩展方法来获取BitArray并返回abool[] 在. 该循环不涉及装箱,因为您将使用's 索引器,并且也可以在没有装箱的情况下枚举 。List<bool>forBitArrayforBitArraybool[] 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())75% 到 85% 的时间foreach (bool b in myBitArray)。每次都会创建列表。创建一次列表并对其进行多次迭代花费了 20% 到 25% 的时间foreach (bool b in myBitArray)bool如果您需要多次迭代这些值并且知道它们从您调用的时间起不会改变,您只能利用这一点myBitArray.ToList()

foreach (bool b in Enumerable.Cast<bool(myBitArray))花费了 150% 的时间foreach (bool b in myBitArray)

另一个编辑:我想说,既然它是一个游戏,你可能会做任何事情来进行非常精简的迭代,没有装箱/拆箱,即使这意味着编写你自己的BitArray. 您可以节省时间并使用Reflector复制大多数studyBitArray的代码,因为该类是密封的(不能继承和添加功能),以防万一有一些小优化可供学习。

编辑:提出从 Reflector 中复制代码的建议。有些东西,比如迭代器和闭包,会产生你不想直接复制的奇怪的生成代码。

于 2009-07-31T18:06:43.027 回答
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];
    }
}

结果(名称、迭代次数、总持续时间、分数(高分不好)):

============ 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
于 2009-08-03T13:58:12.597 回答
2

BitArray<T>如果存在 ,您将传递给的泛型类型参数的示例是什么?

BitArray定义为:

管理一个紧凑的位值数组,表示为布尔值,其中 true 表示该位打开 (1),false 表示该位关闭 (0)。

这种类型是优化的位数组,仅此而已。将其设为通用没有任何价值,因为没有可以从类型中分解出来的成员。任何像这样的特殊集合都可以看作是某个父泛型集合的封闭构造类型。换句话说,BitArray有点像List<Boolean>(当然添加了许多有用的方法)。

编辑: 是的,这种类型实现IEnumerable和不实现IEnumerable<T>- 这很可能是因为它是一个较旧的类型并且没有更新。请记住,您可以使用它Enumerable.Cast<TResult>来解决这个问题:

yourBitArray.Cast<bool>();
于 2009-07-31T18:07:20.060 回答
1

您对通用版本有什么可能的理由?BitArray 可以在位之外使用什么类型,或者根据情况转换为位的布尔值?

更新:它是类型安全的。如果你正在做一个 foreach(var bit in bitArray) 那么 bit 将显示为一个对象,但你可以很容易地做 foreach(bool bit in bitArray),这发生在所有实现 IEnumerable 而不是IEnumerable<T>.

于 2009-07-31T18:07:58.233 回答