Кратко съдържание



страница44/73
Дата21.07.2018
Размер9.03 Mb.
#76887
1   ...   40   41   42   43   44   45   46   47   ...   73

Интерфейсът IComparable


Често пъти освен за равенство е необходимо обектите да се сравняват спрямо някаква подредба (например лексикографска за низове или по големина за числови типове). В .NET Framework типовете, които могат да бъдат сравнявани един с друг, трябва да имплементират интер­фейса System.IComparable.

Интерфейсът дефинира един-единствен метод – CompareTo(object). Този метод трябва да реализира сравняването и да връща:



  • число < 0 – ако подаденият обект е по-голям от this инстанцията

  • 0 – ако подаденият обект е равен на this инстанцията

  • число > 0 – ако подаденият обект е по-малък от this инстанцията

IComparable се използва от .NET Framework при сортиране на масиви и колекции и при някои други операции, изискващи сравнение по големина.

Системни имплементации на IComparable


IComparable е имплементиран от много системни .NET типове, като например от примитивните стойностни типове System.Char, System.Int32, System.Single, System.Double, от символните низове (System.String) и от изброените типове (System.Enum). Това улеснява разработчиците при всекидневната им работа и често пъти им спестява излишни усилия.

Имплементиране на IComparable – пример


В следващия пример е илюстрирано как можем да имплементираме IComparable за потребителски дефинирани типове:

using System;
class Student : IComparable

{

private string mFirstName;



private string mLastName;
public Student(string aFirstName, string aLastName)

{

mFirstName = aFirstName;



mLastName = aLastName;

}
public int CompareTo(object aObject)

{

if (! (aObject is Student))



{

throw new ArgumentException(

"The object is not Student.");

}
Student student = (Student) aObject;

int firstNameCompareResult =

String.Compare(this.mFirstName, student.mFirstName);

if (firstNameCompareResult != 0)

{

return firstNameCompareResult;



}

else


{

int lastNameCompareResult =

String.Compare(this.mLastName, student.mLastName);

return lastNameCompareResult;

}

}

}


class TestIComparable

{

static void Main()



{

Student st1 = new Student("Бате", "Киро");

Student st2 = new Student("Кака", "Мара");
Console.WriteLine(

"st1.CompareTo(st2) = {0}", st1.CompareTo(st2));

// Result: -1


Console.WriteLine(

"st1.CompareTo(st1) = {0}", st1.CompareTo(st1));

// Result: 0


Console.WriteLine(

"st1.CompareTo(42) = {0}", st1.CompareTo(42));

// Result: System.ArgumentException

}

}


В примера се дефинира клас Student, който съдържа две информационни полета – име и фамилия. Имплементацията на CompareTo() извършва лекси­ко­графско сравнение на студенти – първо по име, а след това по фамилия при еднакви имена. Ето как изглежда изходът от примера:


Интерфейсите IEnumerable и IEnumerator


В програмирането се срещат типове, които съдържат много на брой ин­станции на други типове. Такива типове се наричат контейнери или още колекции. Колекции например са масивите, защото съдържат много на брой еднакви елементи.

Често пъти се налага да се обходят всички елементи на даденa колекция. За да става това по стандартен начин, в .NET Framework са дефинирани интерфейсите IEnumerable и IEnumerator.


Интерфейсът IEnumerable


Интерфейсът System.IEnumerable се имплементира от колекции и други типове, които поддържат операцията "обхождане на елементите им в някакъв ред". Този интерфейс дефинира само един метод – методът GetEnumerator(). Той връща итератор (инстанция на IEnumerator) за обхождане на елементите на дадения обект.

Обектите, поддържащи IEnumerable интерфейса, могат да се използват от конструкцията foreach в C# за обхождане на всичките им елементи.

Интерфейсът IEnumerable е реализиран от много системни .NET типове, като System.Array, System.String, ArrayList, Hashtable, Stack, Queue, SortedList и др. с цел да се улесни работата с тях.

Интерфейсът IEnumerator


Интерфейсът System.IEnumerator имплементира обхождане на всички елементи на колекции и други типове. Той реализира прост итератор чрез следните методи и свойства:

  • Свойство Current – връща текущия елемент.

  • Метод bool MoveNext() – преминава към следващия елемент и връща true, ако той е валиден.

  • Метод Reset() – премества итератора непо­средствено преди първия елемент (установява го в начално състояние).

Имплементиране на IEnumerable и IEnumerator


Следващият пример илюстрира как могат да бъдат имплементирани интер­фейсите IEnumerable и IEnumerator, след което да бъдат изпол­звани във foreach конструкция в C#:

using System;

using System.Collections;


class BitSet32 : IEnumerable

{

private uint mBits = 0;



public void Set(int aIndex, bool aValue)

{

if (aIndex<0 || aIndex>31)



{

throw new ArgumentException("Invalid index!");

}
uint bitMask = (uint) 1 << aIndex;
// Set bit aIndex to 0

mBits = mBits & (~bitMask);


if (aValue)

{

// Set bit aIndex to 1



mBits = mBits | bitMask;

}

}


public bool Get(int aIndex)

{

if (aIndex<0 || aIndex>31)



{

throw new ArgumentException("Invalid index!");

}
uint bitMask = (uint) 1 << aIndex;

bool value = ((mBits & bitMask) != 0);

return value;

}
public IEnumerator GetEnumerator()

{

return new BitSet32Enumerator(this);



}
class BitSet32Enumerator : IEnumerator

{

private BitSet32 mBitSet32;



private int mCurrentIndex = -1;
public BitSet32Enumerator(BitSet32 aBitSet32)

{

mBitSet32 = aBitSet32;



}
public bool MoveNext()

{

mCurrentIndex++;



bool valid = (mCurrentIndex < 32);

return valid;

}
public void Reset()

{

mCurrentIndex = -1;



}
public object Current

{

get



{

return mBitSet32.Get(mCurrentIndex);

}

}

}



}
class TestBitSet32

{

static void Main()



{

BitSet32 set = new BitSet32();

set.Set(0, true);

set.Set(31, true);

set.Set(5, true);

set.Set(5, false);

set.Set(10, true);
int index = 0;

foreach (bool value in set)

{

Console.WriteLine("set[{0}] = {1}", index, value);



index++;

}

}



}

Резултатът от изпълнение на примера е следният:


Как работи примерът?


Класът BitSet32 представлява множество от 32 булеви стойности. Той съхранява стойностите си в UInt32 поле като комбинация от битове – по 1 бит за всяка от тях. Методът Set(index, value) изчислява битова маска за зададения индекс, нулира съответния бит и ако е зададена стойност true, го установява след това в единица. Методът Get(index) изчислява битова маска за зададения индекс и връща стойността на съответния бит.

Класът BitSet32 имплементира интерфейса IEnumerable като в метода му GetEnumerator() създава и връща инстанция на специален вътрешен клас BitSet32Enumerator, инициализирана по текущия BitSet32 обект.

Класът BitSet32Enumerator е имплементация на интерфейса IEnumerator. Той съхранява текущия индекс от обхождането на BitSet32 обекта във вътрешна променлива mCurrentIndex. Методът MoveNext() увеличава текущия индекс и ако не е достигнат краят, връща true. Методът Reset() задава стойност -1 за текущия индекс (това е елементът преди първия). Свойството Current връща елемента от текущата позиция.

Главната програма демонстрира правилната работа на класа BitSet32 и имплементацията на интерфейсите IEnumerable и IEnumerator. Тя създава инстанция на BitSet32, променя някои от битовете и отпечатва всички стойности с цикъл foreach.





Сподели с приятели:
1   ...   40   41   42   43   44   45   46   47   ...   73




©obuch.info 2024
отнасят до администрацията

    Начална страница