简体   繁体   English

.NET中是否存在通用(类型安全)BitArray?

[英]Is there a generic (type-safe) BitArray in .NET?

Is there a generic BitArray in .NET? .NET中是否有通用的BitArray? I only found the non-generic one. 我只找到了非通用的。

Can there be a generic BitArray? 可以有一个通用的BitArray吗? (ie would it be reasonable?) (即它是否合理?)


Edit: 编辑:

Maybe I should have said type-safe not generic. 也许我应该说类型安全不通用。

Basically when you enumerate the type as object , should it not be int or bool ? 基本上当你将类型枚举为object ,它应该不是intbool吗? Or one of them provided in another member enumerator? 或者其中一个在另一个成员调查员中提供?


Example: 例:

foreach (bool bit in myBitArray)
{

}

Edit: 编辑:

I just checked the enumerator of the BitArray class, but everything returns an object except .Current property: 我刚刚检查了BitArray类的枚举器,但是除了.Current属性之外,所有东西都返回一个object

public virtual object Current

BitArray is a specialized collection class from the NET 1.x era. BitArray是NET 1.x时代的专业集合类。 It is quite type-safe as long as you use ba.Set(int, bool) and the indexer property. 只要你使用ba.Set(int, bool)和indexer属性ba.Set(int, bool)它就是类型安全的。

What is 'not typesafe' is the enumeration, BitArray implements IEnumerable but not IEnumerable< bool>. 什么是'not typesafe'是枚举,BitArray实现IEnumerable而不是IEnumerable <bool>。 So Joan is right, using foreach() involves casting from object to bool. 所以Joan是对的,使用foreach()涉及从对象转换为bool。

But is that a real problem? 但这是一个真正的问题吗? The elements in a BitArray are booleans, and only meaningful when combined with their position. BitArray中的元素是布尔值,只有与它们的位置结合才有意义。 Note that BitArray does not have an Add() method, just a Set(i, true) . 请注意,BitArray没有Add()方法,只有Set(i, true)

So the simple answer is: don't use foreach() , or anything else based on IEnumerable. 所以简单的答案是:不要使用foreach()或基于IEnumerable的任何其他东西。 It only produces a stream of true/false values that can hardly be useful. 它只产生一个很难用的真/假值流。

In the following snippet the BitArray is perfectly type-safe and efficient: 在下面的代码片段中,BitArray是完全类型安全且高效的:

BitArray isEven = ...;
for(int i = 0; i < isEven.Count; i++) 
{
   isEven.Set(i, i % 2 == 0);
}

No, there isn't. 不,没有。

\n

I'm not even sure what part of a BitArray would be generic if there were one. 如果有的话,我甚至不确定BitArray的哪一部分是通用的。

It wouldn't be hard to create an extension method to take the BitArray and return a bool[] or List<bool> using a for loop on the BitArray . 创建一个扩展方法来获取BitArray并使用BitArray上的for循环返回 bool[] List<bool>并不难。 The for loop would not involve boxing since you would be using the BitArray 's indexer, and the bool[] List<bool> could be enumerated without boxing as well. for循环不会涉及拳击,因为你将使用BitArray的索引器,并且 bool[] List<bool>也可以在没有装箱的情况下枚举。

Example extension method: 示例扩展方法:

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;
}

What I found from a quick benchmark (curiosity overcame me) was that foreach (bool b in myBitArray.ToList()) took 75% to 85% of the time that foreach (bool b in myBitArray) . 我从快速基准测试中发现的(好奇心克服了我)是foreach (bool b in myBitArray.ToList())花费了75%到85%的时间foreach (bool b in myBitArray) That creates the list each time. 这每次创建列表。 Creating the list once and iterating over it many times took 20% to 25% of the time that foreach (bool b in myBitArray) took. 创建一次列表并迭代多次占用foreach (bool b in myBitArray)占用的时间的20%到25%。 You could only take advantage of that if you need to iterate over the bool values multiple times and know that they won't have changed from the time you called myBitArray.ToList() . 如果你需要多次遍历bool值并且知道它们在你调用myBitArray.ToList()时没有改变,你myBitArray.ToList()

foreach (bool b in Enumerable.Cast<bool(myBitArray)) took 150% of the time that foreach (bool b in myBitArray) took. foreach (bool b in Enumerable.Cast<bool(myBitArray))占用了foreach (bool b in myBitArray) foreach (bool b in Enumerable.Cast<bool(myBitArray))占用的150%的时间。

Yet another edit: I'd say that since it is a game, it probably does make sense for you to do whatever it takes to have a very lean iteration with no boxing/unboxing, even if that means writing your own BitArray . 还有另一个编辑:我会说,因为它是一款游戏,所以你可以做任何事情来做一个没有装箱/拆箱的非常精益的迭代,即使这意味着你自己编写了BitArray You could save time and use Reflector to copy most of study BitArray 's code since the class is sealed (can't inherit and add functionality), just in case there are bit-twiddling optimizations to learn from. 您可以节省时间并使用Reflector 复制大部分 学习BitArray的代码,因为类是密封的(不能继承和添加功能),以防万一有点啰嗦的优化需要学习。

Edit: Struck the suggestion to copy code out of Reflector. 编辑:打破从Reflector复制代码的建议。 Some things, like iterators and closures, yield weird generated code that you don't want to copy directly anyway. 有些东西,如迭代器和闭包,会产生奇怪的生成代码,无论如何都不想直接复制。

You can iterate BitArray without boxing or converting it to List<bool> : 您可以在没有装箱的情况下迭代BitArray 将其转换为List<bool>

public static IEnumerable<bool> GetTypeSafeEnumerator(this BitArray ba) {
    for (int i = 0; i < ba.Length; i++)
        yield return ba[i];
}

This should be faster than converting to list and certainly take much less memory. 这应该比转换到列表更快,并且肯定会减少更少的内存。

Of course, it is still going to be slower than a plain old for loop, and if you really need performance, you should use 当然,它仍然比普通的for循环慢,如果你真的需要性能,你应该使用

for (int i = 0; i < ba.Length; i++) {
    bool b = ba[i];
    ...
}

Benchmark using MiniBench : 使用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];
    }
}

Results (name, number of iterations, total duration, score (high score is bad)): 结果(名称,迭代次数,总持续时间,得分(高分为差)):

============ 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

What would be an example of a generic type argument that you would pass to BitArray<T> if it existed? 如果它存在,您将传递给BitArray<T>的泛型类型参数的示例是什么?

BitArray is defined as: BitArray定义为:

Manages a compact array of bit values, which are represented as Booleans, where true indicates that the bit is on (1) and false indicates the bit is off (0). 管理一个紧凑的位值数组,表示为布尔值,其中true表示该位为on(1),false表示该位为off(0)。

This type is an optimized array of bits, nothing else. 这种类型是优化的位数组,没有别的。 There is no value to making it generic as there are no members that could be factored out of the type. 将它作为通用没有任何价值,因为没有可以从该类型中分解出来的成员 Any specialized collection like this one can be though of as a closed constructed type of some parent generic collection. 像这样的任何专门的集合可以作为一些父通用集合的封闭构造类型。 In other words, BitArray is kind of like List<Boolean> (with many useful methods added of course). 换句话说, BitArray有点像List<Boolean> (当然还添加了许多有用的方法)。

Edit: Yes, this type implements IEnumerable and does not implement IEnumerable<T> - this is most likely due to the fact that it is an older type and was not updated. 编辑:是的,这种类型实现IEnumerable并且没有实现IEnumerable<T> - 这很可能是因为它是一个较旧的类型并且没有更新。 Remember that you can use Enumerable.Cast<TResult> to work around this very problem: 请记住,您可以使用Enumerable.Cast<TResult>来解决这个问题:

yourBitArray.Cast<bool>();

What possible reason would you have for a generic version? 您对通用版本有什么可能的原因? What type could a BitArray possibly use beside bits, or booleans which are turned into bits as the the case is? BitArray可能使用什么类型的位,或者根据情况变成位的布尔值?

Updated: It is type safe. 更新:它是类型安全的。 If you are doing a foreach(var bit in bitArray) then bit will appear as an object, but you can just as easily do foreach(bool bit in bitArray), this happens for all collections that implement IEnumerable and not IEnumerable<T>. 如果你正在做一个foreach(bitArray中的var位),那么bit将作为一个对象出现,但你可以很容易地做foreach(bitArray中的bool位),这对于实现IEnumerable而不是IEnumerable<T>.所有集合都会发生IEnumerable<T>.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM