Да си припомним: какво са класовете и обектите?



страница84/84
Дата03.01.2022
Размер0.54 Mb.
#112941
ТипПрограма
1   ...   76   77   78   79   80   81   82   83   84
Класове
Свързани:
Изпитна тема1, Изпитна тема2
CommonOperations.cs

public class CommonOperations

{

// No warning



public void Swap(ref K a, ref K b)

{

K oldA = a;



a = b;

b = oldA;

}

}


По този начин, винаги ще сме сигурни, че няма да има препокриване на заместителите на неизвестните типове на метода и класа.

Използването на ключовата дума default в типизиран код

След като се запознахме с основите на типизирането, нека се опитаме да преработим нашия пръв пример в тази секция – класът описващ приют за бездомни животни. Както разбрахме, единственото, което е нужно да направим е да заменим конкретния тип Dog с някакъв параметър, например T:

AnimalsShelter.cs

public class AnimalShelter

{

private const int DefaultPlacesCount = 20;



 

private T[] animalList;

private int usedPlaces;

 

public AnimalShelter()



: this(DefaultPlacesCount)

{

}



 

public AnimalShelter(int placesCount)

{

this.animalList = new T[placesCount];



this.usedPlaces = 0;

}

 



public void Shelter(T newAnimal)

{

if (this.usedPlaces >= this.animalList.Length)



{

throw new InvalidOperationException("Shelter is full.");

}

this.animalList[this.usedPlaces] = newAnimal;



this.usedPlaces++;

}

 



public T Release(int index)

{

if (index < 0 || index >= this.usedPlaces)



{

throw new ArgumentOutOfRangeException(

"Invalid cell index: " + index);

}

T releasedAnimal = this.animalList[index];



for (int i = index; i < this.usedPlaces - 1; i++)

{

this.animalList[i] = this.animalList[i + 1];



}

this.animalList[this.usedPlaces - 1] = null;

this.usedPlaces--;

 

return releasedAnimal;



}

}


Всичко изглежда наред, докато не се опитаме да компилираме класа. Тогава получаваме следната грешка:

Cannot convert null to type parameter 'T' because it could be a non-nullable value type. Consider using 'default(T)' instead.

Грешката е в метода Release() и е свързана със записването на резултат null в освободената последна (най-дясна) клетка на приюта. Проблемът е, че се опитваме да използваме подразбиращата се стойност за референ­тен тип, но не сме сигурни, дали конкретния тип е референтен или примитивен. Тъкмо затова, компилаторът извежда гореописаните грешки. Ако типът AnimalShelter се инстанцира по структура, а не по клас, то стойността null е невалидна.

За да се справим с този проблем, трябва в нашия код, вместо null, да използваме конструкцията default(T), която връща подразбиращата се стойност за конкретния тип, който ще бъде използван на мястото на T. Както знаем подразбиращата стойност за референтен тип е null, а за числови типове – нула. Можем да направим следната промяна:



// this.animalList[this.usedPlaces - 1] = null;

this.animalList[this.usedPlaces - 1] = default(T);



Едва сега компилацията минава без проблем и класът AnimalShelter<Т> работи коректно. Можем да го тестваме например по следния начин:

static void Main()

{

AnimalShelter shelter = new AnimalShelter();



shelter.Shelter(new Dog());

shelter.Shelter(new Dog());

shelter.Shelter(new Dog());

Dog d = shelter.Release(1); // Release the second dog

Console.WriteLine(d);

d = shelter.Release(0); // Release the first dog

Console.WriteLine(d);

d = shelter.Release(0); // Release the third dog

Console.WriteLine(d);

d = shelter.Release(0); // Exception: invalid cell index

}


Предимства и недостатъци на типизирането

Типизирането на класове и методи води до по-голяма преизползваемост на кода, по-голяма сигурност и по-голяма ефективност, в сравнение с алтернативните нетипизирани решения.

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

Ръководни принципи при именуването на заместителите при типизиране на класове и методи

Преди да приключим с темата за типизирането, нека дадем някои указания при работата със заместителите (параметрите) на непознатите типове в един типизиран клас:

1.  Когато при типизирането имаме само един непознат тип, тогава е общоприето да се използва буквата T, като заместител за този непознат тип. Като пример можем да вземем декларацията на нашия клас AnimalShelter, който използвахме до сега.

2.  На заместителите трябва да се дават възможно най-описателните имена, освен ако една буква не е достатъчно описателна и добре подбрано име, не би подобрило по никакъв начин четимостта на кода. Например, можем да модифицираме нашия пример, заменяйки буквата T, с по-описателния заместител Animal:

AnimalShelter.cs

public class AnimalShelter

{

// ... rest of the code ...



 

public void Shelter(Animal newAnimal)

{

// Method body here



}

 

public Animal Release(int i)



{

// Method body here



}

}


Когато използваме описателни имена на заместителите, вместо буква, е добре да добавяме T, в началото на името, за да го разграничаваме по-лесно от имената на класовете в нашата програма. С други думи, вместо в предходния пример да използваме заместител Animal, е добре да използваме TAnimal.

Сподели с приятели:
1   ...   76   77   78   79   80   81   82   83   84




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

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