هل يوجد BitArray عام (آمن النوع) في .NET؟
سؤال
هل يوجد BitArray عام في .NET؟لقد وجدت فقط واحد غير عام.
هل يمكن أن يكون هناك BitArray عام؟(أي.هل سيكون معقولا؟)
يحرر:
ربما كان ينبغي لي أن أقول النوع الآمن وليس عامًا.
بشكل أساسي عند تعداد النوع كـ object
, ، لا ينبغي أن يكون int
أو bool
؟أو واحد منهم المقدمة في عضو آخر العداد؟
مثال:
foreach (bool bit in myBitArray)
{
}
يحرر:
لقد قمت للتو بفحص العداد الخاص بـ BitArray
فئة، ولكن كل شيء يعود object
يستثني .Current
ملكية:
public virtual object Current
المحلول
لا، لا يوجد.
لست متأكدًا حتى من أي جزء من 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())
استغرق 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
.يمكنك توفير الوقت والاستخدام العاكس ل نسخ معظم يذاكر BitArray
رمز نظرًا لأن الفصل مغلق (لا يمكن وراثة الوظيفة وإضافتها)، فقط في حالة وجود تحسينات طفيفة للتعلم منها.
يحرر: ضرب اقتراح نسخ التعليمات البرمجية من العاكس.بعض الأشياء، مثل التكرارات والإغلاقات، تنتج تعليمات برمجية غريبة لا ترغب في نسخها مباشرة على أي حال.
نصائح أخرى
وBitArray هي فئة مجموعة متخصصة من عصر 1.X NET. فمن من نوع آمنة تماما طالما كنت تستخدم ba.Set(int, bool)
والخاصية مفهرس.
ما هو 'لا typesafe' هو التعداد، BitArray تنفذ IEnumerable ولكن ليس IEnumerable <منطقي>. حتى جوان هو الصحيح، وذلك باستخدام 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);
}
ويمكنك تكرار 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];
...
}
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
ما هو المثال الذي يمكن أن يكون مثالاً على وسيطة النوع العامة التي ستمرر إليها BitArray<T>
إذا كان موجودا؟
BitArray
يعرف ب:
يدير مجموعة مضغوطة من قيم البتات ، والتي يتم تمثيلها على أنها منطقية ، حيث يشير True إلى أن BIT موجود (1) ويشير FALSE إلى أن البت هو (0).
هذا النوع عبارة عن مجموعة محسنة من البتات، ولا شيء غير ذلك.ليس هناك قيمة لجعلها عامة كما هو الحال لا أعضاء التي يمكن أن تؤخذ في الاعتبار من النوع.يمكن اعتبار أي مجموعة متخصصة مثل هذه بمثابة نوع مغلق من بعض المجموعات العامة الأصلية.بعبارة أخرى، BitArray
هو نوع من مثل List<Boolean>
(مع إضافة العديد من الطرق المفيدة بالطبع).
يحرر: نعم، هذا النوع ينفذ IEnumerable
ولا ينفذ IEnumerable<T>
- وهذا على الأغلب لأنه من النوع الأقدم ولم يتم تحديثه.تذكر أنه يمكنك استخدام Enumerable.Cast<TResult>
للتغلب على هذه المشكلة بالذات:
yourBitArray.Cast<bool>();
ما السبب ممكن أن يكون لديك للحصول على إصدار عام؟ ما هو نوع يمكن لBitArray ربما تستخدم بجانب بت، أو القيم المنطقية التي تحولت إلى بت كما كانت الحالة؟
تحديث:
ومن اكتب آمنة. إذا كنت تفعل foreach (فار قليلا في bitArray) ثم قليلا سوف تظهر ككائن، ولكن يمكنك القيام foreach (منطقي بعض الشيء في bitArray) بنفس السهولة، وهذا يحدث لجميع المجموعات التي تنفذ IEnumerable وليس IEnumerable<T>.