C Sharp

објектно оријентисан програмски језик

C# (изговор: /си шарп/), је један од млађих програмских језика. Настао је 2000. године као саставни део Мајкрософтовог развојног окружења .NET Framework 1.0. На челу тима који се бавио развојем C#-а био је Андерс Хејлсберг. C# подржава више парадигми (објектно оријентисану, императивну, декларативну, генеричку) као и већина модерних виших програмских језика. Језик је опште примене и намењен је изради апликација за .NET Framework платформу.

C#
Појавио се2000.; пре 24 године (2000)
Аутор(и)Андерс Хејлсберг
Систем типовастатички
УтицајиC++, Java

Историјат

уреди

Јануара 1999. године, Андерс Хејлсберг основао је тим за израду новог програмског језика који се у почетку звао Кул (eng. "C-like Object Oriented Language"), идејно замишљен као програмски језик C, али објектно оријентисан.[1] Мајкрософт је хтео да сачува првобитно име, али је због заштитног знака одустао.

У јулу 2000. године окружење .NET представљено је на Конференцији професионалних програмера (eng. Professional Developers Conference), језик је преименован у C#, а библиотеке и ASP.NET пренесене у C#. C# представља наследника C и C++ језика, добио је име шарп, инспирисано музичком нотацијом и значи да се написана нота изводи за пола корака више. Фајлови писани у овом језику имају екстензију .cs.

Хејлсберг је главни дизајнер C#-а у Мајкрософту, а раније је радио и на дизајну Турбо Паскала, Делфија и Visual J++. У многим интервјуима и техничким документима он је навео[тражи се извор] да су управо недостаци других програмских језика (нпр. C++, Java, Delphi и Smalltalk) довели до стварања C#.

Џејмс Гослинг, који је 1994. креирао програмски језик Java, и Били Џој, суоснивач Сан-Мајкросистемса (енгл. Sun Mycrosistems) назвали су C# имитацијом Јаве. Тачније, Џејмс Гослинг је изјавио како је C# као Јава којој су искључене сигурност, продуктивност и безбедност.[2][3] Клаус Крефт и Ангелика Лангер (аутори књига о C++-y) навели су у свом блогу да су "Јава и C# готово идентични програмски језици. Досадно понављање без иновација."[4] "Тешко да ће неко тврдити да су Јава и C# језици који су променили начин на који пишемо програме", као и да је "C# много тога позајмио од Јаве и обрнуто. Сада када C# подржава боксинг и анбоксинг, имамо особине веома сличне Јави."[5] У јулу 2000. Хејлсберг је рекао да C# није "Јавин клон" и да је по дизајну ближи C++.[6]

Од издања C# 2.0 у новембру 2005 , језици C# и Јава почињу да се развијају у различитим правцима, а сличности је све мање. Једна од битних разлика јесте додавање генерика у оба језика са веома различитом имплементацијом. C# користи генеричке објекте прве класе (енгл. first-class) који се могу користити као и свака друга класа.[7] Осим тога, C# је додао неколико главних карактеристика по којима би се у великој мери одвајао од других програмских језика и приближио функционалном стилу. Значајне карактеристике су: подржавање ламбда израза, методе проширења и анонимни типови. Ове карактеристике омогућавају C# програмерима да користе технике функционалног програмирања и примењују их кад год је то могуће. Линк (енгл. LINQ) екстензије и функционални увоз (eng. functional import) омогућују програмеру да пише мање кода који се често понавља и користи (нпр. код база података, раздвајање XML) фајла, претраживање података итд. стављајући акценат на програмерску логику како би се побољшала читљивост и одрживост.[8]
C# је имао и своју маскоту која се звала Енди (енгл. Andy), по Андерсу Хејлсбергу. Пензионисана је у јануару 2004. године.

Верзије

уреди

Верзија C# 1.0

уреди

Најављена је 2000. године, а премијерно је приказана 2002. године од стране компаније Мајкрософт. Био је први програмски језик прилагођен за .NET Framework окружење.

Верзија C# 2.0

уреди

У јулу 2003. Мајкрософт је представио спецификацију за C# 2.0 за почетак 2004. године. Ова верзија садржи неке нове могућности програмског језика, од којих је најзначајније да су генерици сада параметризовани типови, много више као што су то били C++ шаблони. Они се имплементирају генерисањем по типу независног бајткода у времену превођења (компајлирања), а када се у времену извршења (енгл. run-time) шаблон први пут инстанцира за конкретан тип, тада се генерише бајткод зависан од типа. Та могућност даје високо-перформансне и много више типизиране генерике који не захтевају много изворног кода.

Верзија C# 3.0

уреди

Визуелни Студио је 2008. добио C# верзију 3.0 која је поседовала много нових функција. То је олакшало програмерима у прављењу својих апликација. Иновације у верзији 3.0:

Верзија C# 4.0

уреди

Први пут представљена у априлу 2010. године. Иновације у верзији 4.0:

  • Касно спајање
  • Опциони параметри

Верзија C# 5.0

уреди

Представљена у августу 2012. године. Главне новине су:

  • Асинхрони чланови
  • Атрибути инфо позиваоца

Верзија C# 6.0

уреди

Представљена у јулу 2015. године. Иновације у верзији 6.0:

  • Статички увоз
  • Филтери изузетака
  • Име оператора

Верзија C# 7.0

уреди

Представљена у марту 2017. године. Новине:

  • Излазне варијабле
  • Торке и деконструкција
  • Подударање узорака
  • Локалне функције
Верзија C# 7.1
уреди

Представљена у августу 2017. године. Подверзија са мањим изменама

  • Асинхроност у функцији Main
  • Предетерминисани изрази са литералима
  • Назначени називи елемената tuple
Верзија C# 7.2
уреди

Представљена у новембру 2017. године подверзија са мањим изменама:

  • Референтна семантика са вредносним типовима података
  • Пренос именованих аргумената
  • Водеће доње црте код нумеричких података
  • Модификатор приватног заштићеног приступа
Верзија C# 7.3
уреди

Представљена у мају 2018. године подверзија са мањим изменама:

  • Лакши приступ фиксним пољима без
  • Поновно додељивање локалних променљивих помоћу резервисане речи ref
  • Коришћење иницијализатора на низовима stackalloc
  • Коришћење фиксних исказа са било којим типом који подржава образац
  • Коришћење додатних генеричких ограничења

Какве апликације можемо писати у C#-у?

уреди

Језик C# нема ограничења у погледу тога какве све апликације можемо направити. C# користи окружење и самим тим нема ограничења у вези са могућим апликацијама. Најчешћи типови прављених апликација:

  • Виндовс апликације - То су рецимо, апликације типа Мајкрософт Офис (eng. Microsoft Office) које имају изглед Виндовса и одлично с слажу са њим. Ово је упрошћено коришћењем модула Виндовс формулара унутар .НЕТ окружења, који у ствари чини библиотека контрола (као што су дугмад, палете алатки, менија итд.) које нам користи при изради Виндовс корисничког интерфејса.
  • Веб апликације- Веб стране које можемо видети кроз било који читач. .НЕТ окружење пружа веома моћан систем генерисања Веб садржаја и то динамички, дозвољавајући персонализацију, сигурност и још много тога.
  • Веб сервиси - представљају нов и узбудљив начин израде разноврсних дистрибуираних апликација. Користећи Веб сервисе преко Интернета можемо размењивати било коју врсту података, користећи просту синтаксу, не водећи рачуна о томе у ком језику је написана апликација нити на ком систему је постављена.[9]

Разлика између C# и C++

уреди

Код у језику C# је мало разумљивији од кода C++. Језик C# је сигурнији по питању доделе типа променљивама. То значи да уколико некој променљивој или неком податку доделимо одређени тип, он не може бити замењен другим типом. Постоје строга правила којих се морамо придржавати приликом конверзија типова, што у суштини значи да ћемо морати да напишемо више кода у C# него у C++-у да бисмо извршили исте задатке. Код је робуснији и једноставније је отклонити грешке, односно .NET у сваком тренутку може одредити ком типу припада тражени податак.

Због тога у C# језику, наредбе као што су „узми део меморије почевши од 4. бајта унутар податка и дужине 10 бајтова и интерпретирај га као X”, што не мора увек да буде лоша особина.

За разлику од C++, C# не подржава вишеструко наслеђивање, иако класа може имплементирати више интерфејса.[10]

Особине језика

уреди

Битно је напоменути да C# програмски језик синтаксно није сложен (има око 80 резервисаних речи), али је врло изражајан у делу где је потребно решити било какав проблем у процесу развоја софтвера. Поред могућности које се тичу саме примене програмских језика, битно је напоменути да C# подржава и следеће:

  • Директан приступ меморији помоћу показивача у стилу C++-а
  • Резервисане речи за издвајање несигурних операција
  • Упозоравање скупљача смећа окружења ЦЛР(CLR) да не уништава објекте на које показују показивачи док се ти објекти не ослободе, итд.

Портабилност

уреди

C# по дизајну најбоље осликава ЦЛИ (енг. Common Language Infrastructure).Спецификације језика не захтевају генерисање ЦИЛ (енг. Common Intermediate Language) или било ког другог специфичног формата, већ се може компајлирати као и традиционални програмски језици C++, Фортран и други.

Методе

уреди

Као код C++, за разлику од Јаве, код C# програмери морају да користе кључну реч virtual како би из подкласе променили наслеђени метод.

Методе проширења дозвољавају програмерима да користе статичке методе, с могућношћу да додају методе објекту.

Не постоје глобалне променљиве нити методе. Све променљиве и функције морају бити декларисане унутар класа.

Приступ меморији

уреди

Показивачи се могу користити само у блоковима означеним са unsafe и потребна је посебна дозвола за покретање. Већини објеката се приступа путем сигурних референци који увек показују на постојеће објекте или имају јасно дефинисану нулту вредност (енг. null), немогуће је добити референцу на непостојећи објекат или на случајни блок меморије. Меморија се не ослобађа експлицитно већ то ради скупљач отпадака (енг.Garbage Collector).

Изузеци

уреди

Традиционални начин обраде грешака у језику C јесте да функција враћа код грешке у случају да се операција не изврши успешно. Проблем са оваквим приступом је да програмер може, случајно или због пропуста да игнорише грешку и у том случају, ако је грешка толико озбиљна, може се доћи у ситуацију да настави са извршавањем и долази до прекида, често с резултатима које корисник не може да разуме.

Изузетак је непредвиђен или неочекивани догађај који спречава програм да настави рад. Може да буде последица програмске грешке, коју претходно није открио преводилац или пак хардверска грешка.

Обрадом изузетака могуће је на елегантан начин одговорити на грешке. Тако извршно окружење ЦЛР, уместо да дође до прекида програма, јавља да се грешка догодила, која се у програму може обрадити, отклонити грешка или прекинути програм на коректан начин. У случају да програм не обради изузетак, извршно окружење ће прекинути програм.

Изузеци и обрада изузетака су примарни механизам за откривање грешака у језику C#. На располагању је синтакса структурне обраде изузетака (енгл. structured exception handeling - SEH). Основни механизам за хватање и обраду изузетака састоји се од испитног блока try , блока за хватање изузетака catch и завршног блока finally, који се пишу између обавезних витичастих заграда. Осим коришћења сва три блокова, могуће је користити и друге комбинације, које укључују само блокове try и finally, без коришћења блока catch. Такође се може користити блок try и један или више catch блокова и у том случају блок finally није обавезан.

Три поменута блока се користе на следећи начин:

  • испитни блок try садржи сумњиве исказе који могу да доводу до изузетка. Његово извршавање се завршава у тренутку када се изузетак догоди
  • блок catch служи за хватање изузетака и њихову обраду. Може бити подешен тако да хвата само одређен тип изузетака. Овом блоку се предаје објекат изведен из класе Exception и неопходно му је задати тип
  • блок finally је завршни поступак у обради изузетка и извршава се увек, било да изузетак није бачен, или да је ухваћен, па чак и у случају када због грешке програм треба да буде прекинут.
try
{
  //испитни блок
}
catch (<Први_тип_изузетка>)
{
  //искази за обраду првог типа изузетка
}
catch (<Други_тип_изузетка>)
{
  //искази за обраду другог типа изузетка
}
catch (Exception e)
{
  //искази за обраду општег типа изузетка
}
finally
{
  //искази који се извршавају
}

Блок за обраду изузетка опште класе Exception, који хвата све изузетке, се поставља као последњи у низу блокова за хватање изузетака. У случају да се овај блок постави на било које друго место, осим на крају свих блокова за хватање, преводилац ће пријавити грешку.

Осим изузетака које изазива ЦЛР, програм може да баца и своје изузетке. Један од честих случајева је када се приликом хватања изузетка, у програму поново убаци исти или неки други изузетак помоћу резервисане речи throw. Изузетак се може бацити и у случају неке неуспешно изведене операције. Да би се бацио нови изузетак, могуће је користити неку од већ постојећих класа изузетака, или извести неку нову класу из класе Exception.

//пример бацања изузетка
  throw (new НамеснкиИзузетак)
//пример изведене класе изузетка из класе Exception
public class НаменскиИзузетак : Exception
{
  //подаци о наменском изузетку
}

Осим класе Exception постоји и велики број изведених класа, од којих свака обезбеђује информације о грешци која је изазвала изузетак. Од тога су само три основне класе за спецификацију класе изузетака.

класа изузетака објашњење
ApplicationException Основна класа за изузетке у именском простору SystemApplication. Изазива се приликом грешака у апликацији које нису фаталне
IOException Основна класа за изузетке у именском простору System.IO. Изазива се приликом улазно/излазних грешака
SystemException Основна класа за изузетке у именском простору System

Осим обраде грешака, по потреби, у језику C# је у оквиру блока за обраду грешке могуће прекинути извршавање програма и за то су на располагању две методе:

  • Environment.Exit(излазниКод) — прекида програм и оперативном систему враћа излазниКод. Дефинисана је у именском простору System. Обично се користи код конзолних програма
  • Aplication.Exit() обавештава све петље порука да морају прекинути рад, затвара све прозоре које је отворила апликација и завршава рад програма, без враћања излазног кода. Дефинисана је у именском простору System.Windows.Forms и обично се користи за излазак из Виндовсових апликација.

Полиморфизам

уреди

Објектно оријентисана парадигма уводи појам наслеђивања, тј. извођења која представља могућност да се једна класа дефинише на основу неке друге класе при чему ће та нова класа да има све особине које има и постојећа класа, неке особине ће бити промењене, а неке нове ће бити додате. То конкретно значи да не морамо да преписујемо постојећу класу познати "копи-пејст" (eng. copy-paste) приступ који се често користи у процедуралном програмирању и представља извор многих грешака) већ само да наведемо од које класе полазимо, односно која је основна или родитељска класа и да модификујемо или додамо неке чланице класе.

class класаОсновна
{
  //Методе, својства и поља чланови основне класе
}

class класаИзведена : класаОсновна
{
  //Методе, својства и поља чланови изведене класе
}

Изведена класа, уз чланове које има основна класа, при чему преузима и њихове нивое приступа декларисане у основној класи.

Не постоји вишеструко наслеђивање, односно свака класа може бити потомак само једне класе. Ову одлуку донео је главни дизајнер језика како би се избегле компликације и поједноставили архитектонски захтеви током ЦЛИ-ја (енг. Common Language Infrastructure).

Полиморфизам који омогућава дописивање метода, могућ је једино преко виртуелних метода. Једном када се метода прогласи виртуелном, метода у изведеној класи може да остане иста као у основној класи, у којем случају се извршава изворна метода у из основне класе или да се измени и изведе и на неки други начин. Као и у случају метода, својства класе такође се могу изменити помоћу виртуалних својстава основне класе, увек када је својство основне класе није декларисано као приватно, у супротном у изведеној класи је неопходно направити засебно поље.

Ако се класа дефинише као апстрактна, онда се она не може користити директно, односно чланове те класе је могуће употребити искључиво ако из ње направи изведена класа. Апстрактна класа се декларише тако што се пре резервисане речи class и имена класе напише apstract.

Пример декларисања апстрактне класе:

abstract class класаАпстрактна
{
  //Чланови класе
}

Ако се покуша декларисати инстанца апстрактне класе, преводилац ће пријавити грешку и неће превести програма Да би се спречило прављење изведене класе од основне, осим коришћења приватних конструктора, који спречавају и само декларисање њене инстанце, постоји и други начин. Извођење класе се може спречити коришћењем резервисане речи saled (запечаћено), којом се окончава ланац наслеђивања.

Пример декларисања запечаћене класе:

saled class класаАпстрактна
{
  //Чланови класе
}

Тако из запечаћене класе није могуће извести нову класу, док апстрактна класа обавезује прављење изведене класа. Модификаторе abstract y saled није могуће користити заједно. За разлику од Јаве, C# подржава преоптерећење оператера.

Омотавање и одмотавање

уреди

У C# користи специјалан тип података object, који прихвата било који податак, вредносног или референтног типа. Када се декларише објекат, у динамичкој меморији се резервише простор за инстанцу променљиве, а тим податком управља извршно окружење. Ако се на пример променљивој типа int додели инстанца типа object, у динамичкој меморији се прави инстанца типа int и та референца се додељује променљивој типа object.

Омотавање (енгл. Boxing) је операција имплицитног претварања променљиве у одговарајући објекат.

Одмотавање (енгл. Unboxing) је операција експлицитног претварања објекта у вредносни тип.

Пример

уреди

Након што се декларише посебан тип структуре:

struct МојаСтруктура
{
  public int Вредност;
}

са именом МојаСтруктура и која садржи један члан Вредност, она се може сместити у објекат типа променљиве и при томе се декларисаном члану може доделити одређена вредност. Ова променљива се може сместити у објекат, у овом случају референтниТип:

  МојаСтруктура промељиваТип1 = new МојаСтруктура();
  промељиваТип1.Вредност = 10;
  object референтниТип = промељиваТип1;

Потом се оваква структура смештена у објекат може претворити у нову променљиву, при чему је на располагању приступање њеном садржају:

  МојаСтруктура промељиваТип2 = (МојаСтруктура)референтниТип;
  Console.WriteLine(промељиваТип2.Вредност);

Резултат ће износити промељиваТип2.Вредност = 10;

Енкапсулација

уреди

Енкапсулација, енкапсулирање што у преводу значи замотавање је начин да ви сакријете, заштитите и контролишете приступ подацима који се налазе у објекту. То радите тако што члановима класе одредите ранг видљивости, тј. одредите који су чланови класе, на пример, јавни, приватни, заштићени или интерни.

Због енкапсулације постоје методе get и set преко којих приступамо атрибутима класа.

Конверзија података

уреди

Постоје разне конверзије, односно претварање између различитих типова података (32-битни у 64-битне бројеве, int у float или string...). Преводилац понекад аутоматски допушта имплицитну конверзију случају да му је јасна природа конверзије, али се при томе смањује прецизност. Тако је на пример променљивој типа long, која у меморији заузима 8 бајтова, могуће доделити вредност 50 типа int, која заузима 4 бајта, али није дозвољено доделити знаковни низ „50”, с обзиром да не може да разуме природу такве конверзије.

У неким случајевима је дозвољена експлицитна конверзија, којом се преводиоцу саопштава да заиста треба извршити конверзију. Оператори конверзије су заправо нови тип податка уписан између заграда.

Имплицитна конверзија:

 long вредност = 50;                //имплицитна конверзија
 int вредност = (long) вредност;    //експлицитна конверзија

Као експлицитну конверзију преводилац ће тумачити и ако се броју дода суфикс по типу. Тако на на пример (long) 50 је исто што и 50L, да би се извршила конверзија у податак двоструке прецизности (double) може се написати 50.0 или 50D, конверзија у податак са покретним зарезом (float) ће се добити додавањем суфикса 50F. Код коришћења новчаних вредности (decimal) није довољно само доделити вредност, већ је извршити конверзију суфикса М (од Money):

 decimal вредност = 50.00M;

За конверзију знаковних низова у број, већина простих нумеричких типова располаже методом Parse():

 string низ = "50";
 int вредност = int.Parse(низ);

Постоје и статичке методе за конверзију из класе Convert:

 string низ = "50";
 int вредност = Convert.ToInt32(низ);

У случају да знаковни низ није могуће претворити у одређени бројни тип, настаће изузетак типа FormatException.

Остало

уреди
  • Језик је Case sensitive, разликује мала и велика слова.

Кључне речи

уреди

Кључне речи C# (верзија 2.0) су: abstract, as, base, bool, break, byte, case, catch, char, checked, class, const, continue, decimal, default, delegate, do, double, else, enum, event, explicit, extern, false, finally, fixed, float, for, foreach, goto, if, implicit, in, int, interface, internal, is, lock, long, namespace, new, null, object, operator, out, override, params, private, protected, public, readonly, ref, return, sbyte, sealed, short, sizeof, stackalloc, static, string, struct, switch, this, throw, true, try, typeof, uint, ulong, unchecked, unsafe, ushort, using, virtual, volatile, void и while.[11]

Примери изворног кода

уреди

Примери се извршавају на конзоли.

Пример 1

уреди

На конзоли се исписује текст ”Здраво свете!”.

using System;
namespace HelloNameSpace
{
  public class HelloWorld
  {
   static void Main()
   {
     Console.WriteLine("Здраво свете!");
   }
  }
}

Пример 2

уреди

На конзоли се исписује текст ”Унесите своје име:” и очекује се унос текста, који се смешта у променљиву име. Након тога на конзоли се исписује текст ”Здраво ” и текст који је унео корисник преко конзоле.

using System;
namespace HelloNameSpace
{
  public class HelloWorld
  {
   static void Main()
   {
      Console.WriteLine("Унесите своје име:");
      String име = Console.ReadLine();
      Console.WriteLine("Здраво " + име);
   }
  }
}

Типови података

уреди

Сваки програмски језик има елементе који га карактеришу и то су :

  • азбука
  • резервисане речи
  • константе
  • променљиве

Азбуку програмског језика C# чине мала и велика слова, цифре, специјални знаци (нпр. за аритметичке операције, релације, итд.) и разделници (тачка, двотачка, тачка зарез, итд.).

Програмски језик C# спада у групу типизираних језика. Свака променљива мора да се декларише пре употребе. Декларацијом променљиве дефинише се : назив, тип, опционо њена почетна вредност и видљивост тј. права приступа (ако је променљива чланица неке класе). У оквиру једне линије кода може се декларисати једна или пак, више променљивих. Свака променљива као карактеристику има:

  • име
  • тип

Име променљиве је низ алфанумеричких карактера, при чему први знак не може бити цифра. Специјални знаци не могу бити део имена осим знака _ (доња црта) који може бити и први знак. Могу се користити мала и велика слова при чему се прави разлика између малих и великих слова.

Тип одређује: скуп вредности, начин представљања у меморији рачунара и скуп оператора који се могу примењивати.

Пример Један од целобројних типова је тип бајт (eng. byte). Скуп вредности који може имати један податак типа бајт је скуп целих бројева у опсегу од -128 до 127. За меморисање једног податка типа бајт потребно је 8 бита. За меморисање једног податка типа инт (eng. int) потребно је 4 бајта, односно 32 бита. Операције које су дозвољене над подацима типа инт су аритметичке операције (сабирање, одузимање, множење и дељење).

Типови података се могу поделити на две велике групе:

  • Вредносни типови:
    • Структуре
      • Нумерички типови података представљају .
        • целе бројеве
          • sbyte — неозначени бајт
          • byte — означени бајт
          • char — уникод знак
          • short — кратак цео број
          • ushort — неозначени кратак цео број
          • int — основни целобројни тип
          • uint — неозначени целобројни тип
          • long — означени дужи целобројни тип
          • ulong — неозначени дужи целобројни тип
        • Типови са покретним зарезом представљају реалне бројеве.
          • float
          • double двоструке прецизности
        • Реални број задате прецизности
          • decimal - обично се користи у рачунским операцијама над новчаним вредностима
      • Логички типови имају само две вредности:логичка истина тј.тачно и логичка неистина, односно нетачно.
        • bool
      • Кориснички дефинисани типови
    • Набројиви типови - енумератори
  • Референтни типови:
    • class
    • interface
    • delegate
    • object
    • string[12]

Целобројни подаци

уреди
тип именски простор.класа дозвољене вредности
sbyte System.SByte целобројна од –128 до 127
byte System.Byte целобројна од 0 до 255
short System.Int16 целобројна од –32.768 до 32.767
ushort System.UInt16 целобројна од 0 до 65.535
int System.Int32 целобројна од –2.147.483.648 до 2.147.483.647
uint System.UInt32 целобројна од 0 до 4.294.967.295
long System.Int64 целобројна од –9223372036854775808 до 9223372036854775807
ulong System.UInt64 целобројна од 0 до 18.446.744.073.709.551.615

Латинично слово u је скраћеница од енглеског unsigned и односи се на бројеве који се пишу без знака (неозначени тип), односно на позитивне бројеве.

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

уреди
тип именски простор.класа формат мин m макс m мин e макс e
float System.Single +/−m × 2e 0 224 -149 104
double System.Double +/−m × 2e 0 224 -1075 970
decimal System.Decimal +/−m × 10e 0 224 -28 0

Набројиве вредности

уреди

Набројиве вредности могу да се односе на само једну вредност или на скуп вредности. Када се направи набројива листа, онда вредности није потребно памтити, већ се њима приступа по имену. Набројиве листе није могуће мењати након доделе вредности.

Декларишу се помоћу резервисане речи enum иза које следи идентификатор за набројиву листу, на коју се надовезују двотачка (:) и тип. Идентификатори се унутар витичастих заграда и раздвојени су зарезима. Дозвољени типови за набројиве листе су byte, sbyte, short, ushort, int, uint, long o ulong. Пример:

Следећа декларација дефинише набројиву листу која почиње са Бројеви.нула која има вредност 0, а завршава се са Бројеви.три која има вредност 3, и сви имају формат long.

enum Бројеви : long
{
  нула, један, два, три
}

Набројиве вредности стандардно почињу нулом и увећавају се за један, али постоји могућност и доделе било ком члану било које друге вредности, док увећање чланова за један остаје:

enum Бројеви : long
{
  нула, три = 3, десет = 10, једанаест, двадесет = 20
}

Мада се набројивој листи придружује основни тип, елементи листе припадају новом типу података, због чега је употребљене вредности неопходно експлицитно конвертовати у основни тип:

  int и = (int) Бројеви.три;

Набројиви тип се може декларисати унутар или ван класе, али у сваком случају листа постаје јавна и може је користити било која класа која има приступ њеном именском простору. Приступ набројивим листама је исти као и приступ променљивама и функцијама. Ако класа садржи набројиви тип, све класе које су изведене из ње наслеђују набројиву листу, коју могу редефинисати и мењати помоћу резервисане речи new. Редефинисање набројиве листе не мења листу основне класе, нити њен код или код било које изведене класе.

Структуре

уреди

Структуре (енгл. structure) су један од најстаријих и најпознатијих механизама за рад с подацима у модерном програмирању. Постојале се у и пре него што се појавило објектно оријентисано програмирање. Подржава их већина програмских језика, а појављивале су се и под другим именима, на пример као слогови (енгл. record) или као блокови (енгл. block).

Структуре представљају колекцију поља података различитих типова, којима се може приступити појединачно или на нивоу групе. Структуре омогућавају да се једним потезом сачува група међусобно повезаних података или пренесе као аргумент приликом позивања функције.

Структура може да садржи конструктор, при чему листа параметара конструктора не може бити празна, али не и деструктор, с обзиром да га наслеђује и не може бити редефинисан.

Користи се као алтернатива класама када објекат садржи углавном податке. Над њима је могуће применити операторе доделе, који директно копирају поља у структури, за разлику од класа којима се додељује референца, али не и садржај. Када се у структурама једна променљива додељује другој, вредност прве се копира у друге, после чега они постају независни и измена садржаја једне структуре, не утиче на вредност друге. Код класа променљиве указују на исти објекат, тако да измена вредности једне утиче на другу.

Структуре се де финишу уз помоћ резервисане речи struct, којој се претходно могу доделити резервисана реч internal, којом се приступ дефиницији структуре ограничава на текући модел. Ако је структура дефинисана у класи, може се доделити било која резервисана реч за приступ. Иза резервисане речи struct пише се име идентификатора. У принципу не постоји конвенција за име, али програмери обично име структуре пишу великим словима, како би се разликовале од класа. Иза имена структуре могу се додати име идентификатори за интерфејс, раздвојених зарезима у случају да их има више. Тело структуре се пише између витичастих заграда, између којих се декларишу њени чланови.

С обзиром да је структура тип података, она може бити декларисана и као повратни тип функције. Структуре су посебно погодне када функција треба да врати више вредности.

Структура може да садржи и инстанце других структура, па чак и класа, али не и сопствену инстанцу јер би то довело до бесконачно рекурзивне дефиниције.

Пример:

Следећа структура дефинише структуру ТАЧКА која би се могла употребити у другој структури ПРАВОУГАОНИК, где се дефинишу његова наспрамна темена, чиме је правоугаоник потпуно дефинисан:

struct ТАЧКА
{
  int осаИкс;
  int осаИпсилон;
}
struct ПРАВОУГАОНИК
{
  ТАЧКА ГорњиЛеви;
  ТАЧКА ДоњиДесни;
}

Инстанца структуре је објекат вредносног типа и са њом се ради као и са било којом другом променљивом вредносног типа. Ако се структура употреби као повратни тип за функцију програм копира цео садржај структуре.

Када се структура користи у променљивама референтног типа неопходно је извршити њену иницијализацију, приликом формирања инстанце. За променљиве вредносног типа постоји подразумевани конструктор који свим члановима додељује вредност 0. Ако се инстанца структуре декларише помоћу оператора new, позива се овај конструктор. Подразумевани конструктор је увек доступан за све вредносне типове и не може се редефинисати код структура, али је структури могуће додати друге конструкторе.

static public void Main()
{
  ТАЧКА т = new ТАЧКА();
  УпотребиСтруктуру(ref т);
}
static public void УпотребиСруктуру(ref ТАЧКА т)
{
  т.осаИкс = 10;
  т.осаИпсилон = 20;
}

Из једне структуре није могуће изводити другу структуру, нити структура може да наслеђује друге структуре. Структуре су изведене из класе Object и наслеђују њене методе, чији подразумевани конструктор не може да бити редефинисан, али су други конструктори могу редефинисати.

Редефинисање неке функције подразумева писање нове функције која носи исто име и исту листу параметара као и наткласа. Редефинисање се врши уз помоћ резервисане речи override у дефиницији објекта, док функција у наткласи мора бити декларисана као виртуелна.

Класа Object садржи методу ToString(), која исписује пуно име објекта, ова функција спада у функције које се могу редефинисати, тако да се може изменити начин на који се добија име структуре.

Да би се приступило пољима структуре, она се морају означити као јавна (public). Подразумевани приступ пољима је иначе приватан, што значи да им могу приступити методе чланице структуре. Над вредностима поља могуће је дефинисати једну или више операција над вредностима поља. У том случају се структури додају нова својства (енгл. property). Својства се понашају исто као и поља, с том разликом што се за рад с њима користе посебне функције get и set. Њима се обезбеђује безбедан приступ приватном пољу.

Оператори

уреди

Типом података је између осталог одређен и скуп оператора који могу да се користе над подацима датог типа. Оператори се могу класификовати по више критеријума. Најчешће се користи класификација на основу броја операнада и класификација у односу на врсту израза у којима се користе. По првој класификацији оператори могу бити :

Унарни оператори су оператори који имају само један операнд. Такав је на пример оператор негације.

Бинарни оператори се примењују над два операнда и они су најчешћи. Пример бинарних оператора су оператори за сабирање, одузимање, множење итд.

Тернарни оператор има три операнда и у програмском језику C# постоји само један такав оператор (тај оператор је оператор „?:” који ће накнадно бити описан).

По другој класификацији оператори се могу поделити на:

  • аритметичке(нумеричке),
  • логичке,
  • релацијске,
  • операторе за рад са текстуалним подацима.

Аритметички оператори

уреди

Аритметички оператори су :

  • +(сабирање)
  • -(одузимање)
  • *(множење)
  • /(дељење)
  • %(остатак целобројног дељења — модуо)

Логички оператори

уреди

Логички оператори су:

  • ! -негација
  • ||-логичко "или"
  • &&-логичко "и"

Оператори поређења

уреди

Оператори поређења или релацијски оператори су:

  • == — еквиваленција, односно једнакост
  • != — нееквиваленција, односно различито или неједнакост
  • < — мање
  • > — веће
  • <= — мање или једнако
  • >= — веће или једнако

Резултат је логичког типа и може имати вредности тачно (енгл. true) или нетачно (енгл. false).

Условни оператори

уреди

Условни оператори на C# језику врше поређење искључиво две вредности логичког типа. За разлику од неких других програмских језика, није могуће поредити било какве бројне вредности, осим логичких.

Пример

уреди

На C++ могуће је поредити бројне вредности а и б:

if (а && б)
  исказ;

док ће такав исказ на C# пријавити грешку. Због тога је за операнде који нису логичког типа, неопходно написати код који ће се прилагодити логичком типу:

if ((а!=0) && (б!=0))
  исказ

Тернарни условни оператор ?:

уреди

На C# има само један тернарни условни оператор, који додељује променљивој једну од задатих вредности, зависно од услова. Овај тернарни оператор додељуј услов иза којег следи знак питања, а затим израз који се извршава у случају да је резултат резултат тачан, па потом израз који се извршава у случају да услов није тачан:

променљива = услов ? : израз1 : израз2;

У претходном исказу, променљива добија вредност првог израза (израз1) у случају да је услов тачан, а ако је услов нетачан, додељује се вредност другог израза (израз2). Осим тога тип променљиве и тип резултата који се добија из једног и другог израза морају бити исти.

Оператор ??

уреди

(енгл. null-coalescing) оператор испитује услов где је вредност празна, односно једнака null. Израз враћа вредност левог операнда у случају да она није празна, у супротном враћа десни операнд. Да би се могао користити овај оператор потребно је претпоставити да вредност операнда може бити празна.

Пример:

могућаПразнаВредност ?? вредностАкоЈестеПразна

Оператор је могуће употребити и више пута у истом изразу.

Пример:

return вредност1 ?? вредност2 ?? вредност3;

Операција се завршава чим се додали нека вредност која није празна или ако се дође до последње вредности, која може али не мора бити празна.

Бит оператори

уреди

Оператори за рад са битовима су:

  • ~ — негација на нивоу бита
  • & — И на нивоу бита
  • | — Или на нивоу бита
  • ^ — ексклузивно или на нивоу бита
  • << — померање улево
  • >> — померање удесно

Текстуални оператори

уреди

Текстуални оператор је конкатенација у ознаци + и представља надовезивање другог операнда на први операнд.

Оператор додељивања

уреди

Поред претходно наведених оператора који се најчешће користе, постоје и други оператори као што су оператори доделе, оператори за инкрементирање, оператори за декрементирање, тернарни оператор итд.

Основни оператор доделе је =. У општем случају оператор доделе се користи на следећи начин:

променљива=израз

Најпре се израчунава израз, а затим се израчуната вредност израза додељује променљивој, при чему типови израза и променљиве морају да се сложе.

Поред основног оператора доделе постоје и сложени облици оператора доделе који имају општи облик

оператор= где је оператор било који аритметички оператор.


Оператор пример резултат
= а = б променљивој а се додељује вредност променљиве б
+= а += б променљивој а се додељује сума вредности променљивих а и б (а = а + б)
-= а -= б променљивој а се додељује разлика вредности променљивих а и б (а = а - б)
*= а *= б променљивој а се додељује вредност множења променљивих а и б (а = а * б)
/= а /= б променљивој а се додељује вредност дељења променљиве а са б (а = а / б)
%= а %= б променљивој а се додељује вредност остатка при дељењу а са б (а = а % б)

Напомена : оператори додељивања = и += се могу користити и код текстуалних променљивих, а оператор %= је дозвољени искључиво над целобројним операндима.

И поред тога што се у следећим исказима:

 а = а + 12;
 а += 12;

добија исти резултат, између њих постоји велика разлика. У првом исказу, програм ће два пута учитати променљиву, први пут пре извршавања првог израза, при чему ће направити његову привремену копију, а други пут непосредно пре извођења доделе када ће сабирање извршити над копијом, док ће у другом случају учитавање променљиве извршити само једном.

Мада разлика изгледа небитна, она се посебно може приметити у следећем примеру;

  int и = 0;
  int [] низ = new int [10];
  while (и < 10)
  {
    низ[и++] += 50;
  }

Ако би уместо:

  низ[и++] += 50;

написали:

  низ[и++] = низ [и++] + 50;

вредност бројача и би се увећао два пута.

Над битовима целобројних операнда могуће је применити и следеће сложене операторе додељивања:

Оператор пример операција
&= а &= б конјукција над битовима вредности променљиве а и променљиве б
= а != б дисјункција над битовима вредности променљиве а и променљиве б
^= а ^= б искључива дисјункција над битовима вредности променљиве а и променљиве б
>>= а >>= б помера бит у вредности променљиве а удесно б пута
<<= а <<= б помера бит у вредности променљиве а улево б пута

Оператори инкрементирања и декрементирања

уреди

Оператори инкрементирања у ознаци ++ и декрементирања у ознаци -- могу бити префиксни и постфиксни. Оператор инкрементирања повећава вредност операнда за један, а оператор декрементирања смањује вредност операнда за један и то без обзира да ли су префиксни или постфиксни. Разлика се уочава једино када су ови оператори део неког сложенијег израза. У том случају се оператори инкрементирања и декрементирања, ако су у префиксном облику извршавају пре рачунања вредности израза, за разлику од случаја када се јављају у постфиксном облику када се извршавају тек након израчунатог израза. Једноставно речено, ако се у неком изразу оператори инкрементирања и декрементирања јављају у префиксном облику вредност израза се израчунава са новим вредностима операнада над којим се примењују ови оператори, односно у случају постфиксних оператора израз се рачуна са старим вредностима операнада.

Оператор израз резултат
++ ++а променљива а се увећава за 1 (а = а + 1).
-- --а променљива а се умањује за 1 (а = а - 1).
++ а++ променљива а се увећава за 1 (а = а + 1).
-- а-- променљива а се умањује за 1 (а = а - 1).
++ а = ++б променљивој а се додељује вредност б + 1. Променљива б се увећава за 1 (б = б + 1).
-- а = --б променљивој а се додељује вредност б - 1. Променљива б се умањује за 1 (б = б - 1).
++ а = б++ променљивој а се додељује вредност б, након чега се променљива б увећава за 1 (б = б + 1).
-- а = б-- променљивој а се додељује вредност б, након чега се променљива б умањује за 1 (б = б - 1).

Пример 1

уреди

Након обављених операција:

int а, б = 5, в = 6;
а = б++ * --в;

променљиве ће имати следеће вредности:

а = 25
б = 6
в = 5

Пример 2

уреди

И поред тога што преводилац C# игнорише вишак размака, у случају сложених оператора, раздвајање симбола размацима може довести до пријаве грешке или погрешног тумачења, са нежељеним резултатима. Када су упитању оператори инкрементирања и декрементирања, у префиксном облику, преводилац неће пријавити грешку, али ће их протумачити као двоструку примену унарног оператора

int а, б = 5;
а = + +б;

Резултат:

а = 5;
б = 5;

У случају суфиксног облика са размацима преводилац ће пријавити грешку због недостатка операнда на десној страни.

int а, б = 5;
а = б+ +;

Резултат:

нема резултата пријављује се грешка

Оператори над типовима

уреди

Како је C# језик са строгом провером типова, у њему је помоћу рефлексије, током извршавања програма могуће одредити стварни тип података. Операције за одређивање типова омогућене су захваљујући класи System.Type.

Оператор tipeof враћа тип објекта као променљиву те класе, а информације о члановима објекта могуће је добити без инстанцирања те класе.

Оператор is проверава да ли је могуће неки објекат конвертовати у одређени тип, што може бити посебно корисно у методама за обраду догађаја, као што су Виндоусове контроле, код којих је пошиљалац (енгл. sender) најчешће типа object.

Оператор sizeof

уреди

Користи се за читање величина података у бајтовима искључиво вредносних типова података. Може се применити и код структура, уколико не садрже чланове референтног типа, односно не садрже променљиво типа string или низ.

Пример:

namespace Величине
{
  using System;
  struct Тестирање 
  {
     int и;
     double д;
     char к;
  };
  class ГлавнаКласа
  {
    static public unsafe void Main()
    {
      Console.WriteLine("Величина булеановог типа " + sizeof(bool));
      Console.WriteLine("Величина карактера је " + sizeof(char));
      Console.WriteLine("Величина целобројног типа је " + sizeof(int));
      Console.WriteLine("Величина означеног целобројног типа је " + sizeof(long));
      Console.WriteLine("Величина типа двоструке прецизности је " + sizeof(double);
      Console.WriteLine("Величина структуре за тестирање је " + sizeof(Тестирање));
    }
  }
}

Изрази

уреди

Синтаксно исправна комбинација операнада и оператора представља један израз. Израз, тачније речено вредност израза, такође има свој тип који може да буде један од стандардних типова (целобројни, реални, логички,...).

Пример израза: alfa - 3 * pom + beta Ако се у једном изразу појави више оператора поставља се питање којим редоследом ће они бити примењивани, односно извршавани. Сваки оператор има свој приоритет. Редослед примене оператора зависи од приоритета оператора који се срећу у једном изразу. Ако имамо више оператора истог приоритета онда се у неким случајевима они примењују слева удесно тј. онако како се појављују у изразу. Поред познавања начина функционисања оператора треба знати и приоритет оператора и редослед извршавања ако се јави више њих узастопно.

Ако експлицитно желимо одговарајући редослед извршавања оператора, онда користимо заграде. У општем случају се најпре примењују они оператори који се налазе у заградама. Ако имамо случај угњеждених заграда онда се најпре примењују најдубље заграде.

Приоритет оператора

уреди

Сви оператори имају свој приоритет. Компајлер извршава неки израз у коме постоји више оператора у редоследу који се одређује на основу приоритета оператора и места њиховог појављивања у изразу. Неки оператори имају исти приоритет, односно сви оператори се могу сврстати у категорије. Приоритет ових категорија (од највишег ка најнижем) је следећи :

  • основни оператори (приступ пољу, позив методе, приступ индексу, постинкрементирање, постдекрементирање,"new","typeof","sizeof")
  • унарни оператори
  • аритметички (множење, дељење, остатак при дељењу)
  • сабирање и одузимање
  • померање на нивоу бита(померање улево и померање удесно)
  • релациони оператори
  • једнакост (једнако или различито)
  • И на нивоу бита
  • ексклузивно ИЛИ на нивоу бита
  • ИЛИ на нивоу бита
  • логичко И
  • логичко ИЛИ
  • тернарни оператор
  • оператор додељивања

Искази

уреди

Исказ је најмања јединица програмског језика. Искази могу бити прости или сложени. Прост исказ се завршава тачком и зарезом ”;”, док се сложени искази пишу унутар витичастих заграда између којих може стајати произвољан број исказа. Сложени искази се често користе у петљама или условним изразима.

Искази могу да се пишу у више редова при чему се ознаке за крај реда игноришу. Такође је могуће написати више исказа у истом реду.

Декларисање и коришћење променљивих

уреди

Променљива у програмирању означава именовану меморијску локацију која је подобна за складиштење одређеног податка. У сваком тренутку извршења програма она садржи тачно одређену вредност која се у сваком тренутку може заменити другом вредношћу. Смештање вредности и операције над променљивама њима зависи од типа. C# је језик са строгом провером типова података, што значи да се променљивој мора доделити тип пре него што се употреби у програму, јер је преводиоцу неопходно да зна колико ће меморије заузети за сваку променљиву. Осим тога, да би се променљива употребила у програму, неопходно је да јој буде додељена нека вредност, а декларисање типа и додела вредности могу се извршити у истом кораку.

У следећем примеру се користи променљива „наслов” која се декларише као референтни тип string и којој се истовремено додељује вредност ”Увод”:

string наслов = "Увод”
Console.WriteLine("Прво поглавље књиге гласи " + наслов);

Уз помоћ оператора + су спојене ниске типа константе и типа променљиве, које се штампају на излазној конзоли штампају следећи резултат:

Прво поглавље књиге гласи Увод

Исти резултат се може добити коришћењем методом интерполације, односно коришћењем специјалног симбола долар $ испред наводника и уметањем променљиве између витичастих заграда {}, како би интерпретатор (рачунарство) у тексту на излазу заменио назив променљиве њеном вредношћу:

string наслов = "Увод”
Console.WriteLine($"Прво поглавље књиге гласи {наслов}”);

Интерполација ниски је карактеристика C# од верзије 6. и омогућава читљивију и удобнију синтаксу за рад са нискама.


Референтни типови података

уреди

Референце омогућавају индиректан приступ објекту, често се називају и алијаси, јер се увек односе на на постојећи објекат. Референца се мора иницијализовати приликом декларисања, а објекат који референцира се не може променити.

Променљиве референтног типа чувају референце на објекте класа, низове, делегате и интерфејсе. Члановима објеката се приступа уз помоћ оператора (.) тачка.

Класе

уреди

Основни механизам путем којег C# остварује принципе објективно оријентисаног програмирања су класе. Као објективно оријентисан програмски језик, захтева се постојање макар једног објекта, односно класе, која садржи код програма. Класа служи као контејнер за податке (као што су поља и константе) и функције.

Класу дефинише резервисана реч class, иза које следи идентификатор, односно име класе иза којег следе витичасте заграде. Унутар класе се дефинишу променљиве и функције који представљају њене чланове.

class имеКласе
{
  //следе променљиве и методе који су чланови класе
}

Већина библиотечких класа се налази у именском простору System. Да би се могло приступити објекту у том именском простору потребно је написати комплетно име објекта. Тако на пример, да би се приступило класи Console у именском простору System, потребно је користити име System.Conslole. Пример позивања функције WriteLine() у класи Console:

class clsMain
{
  static public void Main()
  {
    System.Console.WriteLine("Здраво свете");
  }
}

Ова синтакса се може скратити употребом резервисане речи using, којом се преводиоцу указује на приступ одређеном именском простору у коме треба да пронађе одређени идентификатор. Пример:

using System;
class clsMain
{
  static public void Main()
  {
    System.Console.WriteLine("Здраво свете");
  }
}

Резервисана реч using мора стајати ван класе, у супротном ће преводилац пријавити грешку.

Низови

уреди

Низ је група променљивих истог типа, којима се приступа помоћу индексног броја. Декларисањем и пријављивањем низова се заправо ствара инстанца класе System.Array, која се бави додељивањем меморије за чланове низа. Њен конструктор је заштићен, није могуће инстанцирати је, већ се то чини приликом декларације у складу са различитим правилима.

Низ се декларише тако што се прво напише тип податка, иза кога следе угласте заграде, па идентификатор низа. Инстанца низа се прави помоћу оператора new, иза кога следи тип податка и величина низа смештена између угластих заграда.

int [] низ;
низ = new int [5];

Постоји могућност да се низ декларише и формира у истом програмском реду;

int [] низ = new int [5];

Индекс првог елемента низа је увек 0 (и не постоји могућност индексирања који почиње од броја 1), а број индекса последњег елемента је за један мањи од броја чланова низа. Опсег низа се проверава и у случају приступа непостојећем члану низа настаје изузетак IndexOutOfFange.

Класа System.Array има неколико метода за сортирање и претраживање низа. За претраживање одређене вредности елемента низа користи се метода Indexof(), која враћа индекс првог елемента задате вредности, док метода LastIndexOf() враћа индекс последњег елемента у коме се појављује задата вредност. Обе методе су статичке и враћају вредност -1 у случају да тражена вредност не постоји у низу. Постоји могућност задавања почетне позиције.

За сортирање се користи метода Sort(), која елементе низа уређује од најмање до највеће вредности, односно растућем редоследу. Постоји и метода за обртање редоследа елемената Reverse(), која елементе низа ређа по опадајућем редоследу, након што су они претходно поређани по растућем редоследу. Пример:

int [] низ = new int [5]{30, 5, 8, 21, 6};
Array.Sort(низ);
foreach (int члан in низ)
{
  Console.Write(члан + " ");
}
Array.Reverse(низ);
foreach (int члан in низ)
{
  Console.Write(члан + " ");
}

Резултат:

 5 6 8 21 30
 30 21 8 6 5

Низови се могу копирати помоћу методе Copy(), при чему копирају елементи једног низа у други. Могућа је и имплицитна конверзија типова, на пример низ типа int у низ типа double. Ако се покуша копирање низа типа double у низ типа int, преводилац неће пријавити грешку, али ће приликом извршавања програма настати изузетак типа ArrayTypeMismatchException.

Приликом копирања није неопходно копирати цео низ, већ само одређен број елемената. Постоје две верзије методе копирања:

Array.Copy(извор, одредиште, број);

где је потребно навести изворишни и одредишни низ, као и број елемента који се копирају, почевши од првог елемента низа. Други облик је

Array.Copy(извор, почетакИзвора, одредиште, почетакОдредишта, број);

у коме се наводе почетне позиције за копирање. Низ је могуће направити од било ког типа података, укључујући структуре и класе. То значи да низ може садржати методе, својства и поља. Пример:

класа [] низ = new класа[10];

Међутим, да би се могли уредити низови у растуће и опадајуће, неопходно је реализовати интерфејс IComparable који ће садржати методу CompareTo(). У случају да се не реализује IComparable са методом за поређење, метода Sort() изазива изузетак типа InvalidOperationException.

Индексери

уреди

Осим што класе могу да формирају део низа, оне могу да се користе за управљање низом. У том случају се користе индексери, који омогућавају да објекат класе садржи друге објекте који могу бити индексирани, тако да се третира као да је низ, мада он то није. На пример, код класа за базе података објекат управља редовима у табелама и омогућује учитавање њихових колона.

Индексери се декларишу на исти начин као и својства, употребом синтаксе this [], због чега су индексери увек чланови инстанце. Потребан им је најмање један параметар, а могу их имати и више и мора имати повратни тип. Декларација почиње задавањем нивоа приступа, затим повратног типа, који не може бити void, иза којег следи резервисана реч this, а за њом параметри између угластих заграда. Након угластих следе витичасте заграде, а између њих обавезно морају да стоје методе get или set или обе.

Пример:

public int this[int индекс]
{
  get
  {
    //код за реализацију методе за приступ get
  }
  set
  {
    //код за реализацију методе за приступ set
  } 
}

Индексере је у Визаул Студију могуће креирати уз помоћ чаробњака за индексере (енгл. Indexer Wizard).

Интерфејси

уреди

Интерфејс је потпуно апстрактна класа и сви његови чланови су имплицитно апстрактни и јавни. Интерфејс не може да садржи поља. Није могуће директно направити инстанцу интерфејса.

Интерфејсом се дефинише одређено понашање које класа треба да има. Користи се само као основа из које се изводе класе или други интерфејси. Свака класа која наслеђује интерфејс мора да реализује сваку методу или својство који су дефинисани у интерфејсу. Интерфејс не може да садржи конструкторе. У случају да преводилац у интерфејску наиђе на употребу резервисане речи static примењену на чланове, он јавља грешку. Интерфејс се дефинише исто као и класа, име интерфејса се наводи након резервисане речи interface. Име се према неписаном правилом пише великим латиничним словом И. У случају да се дефинише неко својство, оно мора да садржи најмање једну од метода get или set за приступ.

Пример:

interface IМојИнтефејс
{
  void Метода();
  int Својство
  {
    get;
  }
}

Приликом реализовања овог интерфејса, изведена класа мора да дефинише најмање једну методу и get или set за њен приступ:

class Класа : IМојИнтерфејс
{
  public void Метода()
  {
    //реализација методе
  }
  public int Својство
  {
    get {return (0);}
  }
}

Испред методе и својства стоји резервисана реч public.

class Класа : IМојИнтерфејс
{
  public void Метода()
  {
    //реализација методе
  }
 public int Својство
  {
    get {return (0);}
  }
}

Интерфејс постаје особина класе, која се може исписати оператором is.

public void некаМетода()
{
  Класа објекат = new Класа();
  if (објекат is IМојИнтерфејс)
  {
    //код у зависност од IМојИнтерфејс
  }   
}

Интерфејси су обично кратки и дефинишу тек неколико елемената које би класа требало да реализује. Њихова предност у односу на апстрактне класе је томе што код класа није обавезно ниједан апстрактни члан, док интерфејс осигурава да ће било које дефинисано својство својство или метода бити реализовани у изведеној класи.

Делегати

уреди

Делегат је сличан интерфејсу, с том разликом што делегат декларише само једну методу. Остварује се кроз класу System.Delegate, која може да садржи и адресу инстанце класе и показивач на методу.

Постоје две врсте делегата:

  • једносмерни (енгл. single-cast). Позива само једну методу и може да врати вредност било ког типа.
  • вишесмерни (енгл. multi-cast). Дозвољава доделу више метода, при чему не постоји могућност враћања вредности, односно њен повратни тип је void.

Делегати се обично користе код догађаја (енгл. events). Објекат користи догађај да би обавестио други објекат да се нешто догодило, где више објеката може да ослушкује исти догађај, а њихове методе ће бити позване оним редоследом којим су регистроване. Делегати за системске догађаје су увек вишесмерни.

Облик метода која реагују на догађаје мора одговарати облику декларисаног делегата.

Именски простор

уреди

Именски простор декларише област важења класа и помаже организовању програмског кода. Како би се избегло понављање имена, програмски склопови језика C# штите класу помоћу скупа именских простора. Именски простор дефинише логички простор за идентификаторе. Идентификатори, односно имена класа морају бити јединствени у оквиру једног именског простора, али је довољно да се поклапају са именима класа у другим именским просторима.

Именски простор се декларише уз помоћ резервисане речи namespace, након чега се пише његово име и затим чланови између витичастих заграда. Чланови именског простора могу бити класе, интерфејси, делегати, набројиви типови и структуре. Исти именски простор може се користити у више датотека. Именски простори могу бити дефинисани и сами, равноправно са системским именским просторима окружења.

.NET са којим се испоручује C# садржи два основна именска простора. Први именски простор је System, који дефинише основне класе и сервисе. Између осталих, System садржи класу Console.

Други именски простор .NET окружења је Microsoft, која садржи класе за превођење и прављење кода у језицима које подржава .NET, као и класе које се односе на системске догађаје и коришћење базе Registry.

Именски простори могу да садрже друге именске просторе. Спољни именски простор се назива основни или именски простор првог нивоа. Угњеждени именски простор се зове потпростор, или простор другог нивоа. Именски простори се могу угњежђивати до неограничене дубине, али се ретко користи више од два нивоа.

Пример угњеждених именских простора:

namespace ИП1 // ИП1
{
  class К1        // ИП1.К1
  {
    class К2      // ИП1.К1.К2
    {

    }
  }
  namespace ИП2   // ИП1.ИП2
  {
    class К2      // ИП1.ИП2.К2
    {

    }
  }
}

Именски простор ИП1 је члан глобалног именског простора. ИП2 је члан именског простора ИП1, његово пуно име (енгл. fully qualified name) гласи ИП1.ИП2. Пуно име именског простора у програму мора бити јединствено. Класа К1 је члан именског простора ИП1, а њено пуно име је ИП2.К1. Класа К2 се користи два пута у програму, али су у питању два јединствена пуна назива. Прва инстанца класе К2 је дефинисана у оквиру класе К1, где њено пуно име гласи ИП1.К1.К2, а друга инстанца класе К2 је декларисана у оквиру именског простора ИП2 и њено пуно име је ИП1.ИП2.К2.

Да би се избегло коришћење пуног имена за сваку класу у програму објектима именског простора је могуће прићи коришћењем резервисане речи using. На пример, ако да би се користили чланови класе Console именског простора System можемо може се написати овако:

System.Console.Write("Текст");

Уместо пуног имена може се декларисати коришћење именског простора System и затим користити директно имена његових класа, као у следећем примеру:

using System
class МојаКласа
{
  Console.Write("Текст");
}

У овом случају резервисана реч using је употребљена као команда и она мора бити коришћена ван било које дефиниције класе. Уз помоћ резервисане речи using могуће је направити и алтернативно име, односно алијас (рачунарство), за класу или за именски простор. Употреба алијаса посебно је корисно када се иста имена класа појављују у различитим именским просторима.

Резервисану реч using могуће је користити и као исказ.

Функције

уреди

У целом програму, најмање једна класа садржи функцију Main() и она представља полазну тачку програма. Оперативни систем покреће програм, тако што покреће управо ову функцију. Програм редом извршава исказе функције Main(), а по извршавању последњег, програм враћа контролу оперативном систему.

Приликом дефинисања функције, неопходно је дефинисати њен повратни тип. Функције обично враћају одређени тип, а ако функција не треба да врати никакву вредност, онда је њен повратни тип void. Повратни тип функције Main() мора бити или void или int. Ако се одреди да функција Main() буде типа int, она мора да се заврши исказом return, којом се враћа нека целобројна вредност оперативном систему. Након дефинисања повратног типа функције, налази се име функције, које мора почињати неким великим или малим словом или доњом цртом. Име функције не може садржати операторе. Дефиниција функције може садржати листу параметара, који се пишу унутар заграда. Листа садржи типове података и имена параметара, међусобно раздвојене зарезима. Након затворене заграде пишу се искази које функција извршава. Сваки програм мора садржати најмање једну класу и једну функцију. Функција Main() такође може садржати листу параметара, где се обично користи само један параметар у облику низа типа string:

static int Main(string [ ] аргументи)
{
  //искази
  return (0);
}

Коментари

уреди

Једнолинијски коментари се пишу иза две косе црте //. Сав текст који долази иза њих до краја линије сматра се коментаром. Вишелинијски коментари се пишу између косих црта и звездице, односно између /* и */.

Пример

уреди
using System;
namespace РадниПростор
{
  public class Програм
  {
   static void Main()
   {
      //једнолинијски коментар
      /* Вишелинијски 
         коментар */
      Console.ReadLine(); 
   }
  }
}

Нити

уреди

Нит (енгл. thread) је изолована путања извршавања у програму. Она има сопствени простор на стеку и може да извршава методе и прави објекте истовремено са главном путањом извршавања (главном нити) у програму. Нити омогућавају извршавање дела програма одвојено од главне путање извршавања програма. Обично се користе за дуготрајне обраде података у позадини, док главна нит и даље сарађује са корисником.

Нити су престављене класом Thread у именском простору System.Threading. Покретање нити се врши задавањем почетне методе објектом класе ThreadStart. Класа Thread садржи неколико статичких метода које се позивају без инстанцирања класе, као што су метода Start() која покреће нит, метода Sleep(), којом се текућа нит зауставља за одређени број милисекунди и метода Join() која чека да се нит заврши.

using System;
using System.Threading;
namespace нити
{
  class главнаКласа
  {
     static public void Main()
     {
       //Објекат типа нити
       Thread нит = new Thread(new ThreadStart(Старт));
       //Покреће нит
       нит.Start();
       //Чека да се нит заврши
       нит.Join();
     }
     static void Старт()
     {
        Console.WriteLine("Инстанцирана нит");
     }
  }
}

Писање конзолних програма

уреди

Конзолни програми су најједноставнији облик C# програма. Изворни програм је могуће написати у обичном програму за обраду текста, као на пример у Ноутпеду. C# преводилац не узима у обзир екстензију датотеке, али се за датотеке у изворном коду у C# препоручује наставак cs.

Функција Console.Write() је најсличнија функцији printf() из језика C++. Исписује излазну секвенцу. Излазне секвенце могу садржати:

Излазна секвенца Значење
\a звоно, производи кратак звучни сигнал
\b помера за једно место улево
\f помера излаз на почетак следеће стране на штампачу, а на екрану исписује контролни знак
\n помера курсор на почетак следећег реда
\r текст који се исписује на екрану после овог знака, појављује се преко текућег садржаја реда
\t знак за табулатор
\v вертикални табулатор. На екрану даје контролни знак
\" наводници. користи се као граничник за знаковне низове. у комбинацији са косом цртом преводилац га тумачи као обичан знак
\\ исписује обрнуту косу црту

Функција Console.WriteLine() исписује текстуалну представу одређеног објекта, иза које следи излазна секвенца за завршетак реда, чија је предодређена вредност „\r\n”. Ову вредност је могуће променити, променом карактеристике NewLine, класе TextWriter из именског простора System.IO.

Примери

уреди

Пример 1:

string ниска1 = "Ниска 1", ниска2 = "Ниска 2";

Console.Write(ниска1);
Console.Write(ниска2);

Резултат:

 Ниска 1Ниска 2

Пример 2:

string ниска1 = "Ниска 1", ниска2 = "Ниска 2", ниска3 = "Ниска 3",
       ниска4 = "Ниска 4", ниска5 = "Ниска 5";
Console.Write(ниска1 + "\t" + ниска2 + "\n" +
              "\"" + ниска3 + "\"" + "\r\n" +
              ниска4 + "\\" + ниска5);

Резултат:

Ниска 1	Ниска 2
"Ниска 3"
Ниска 4\Ниска 5

Пример 3:

string ниска1 = "Ниска 1", ниска2 = "Ниска 2";

Console.WriteLine(ниска1);
Console.WriteLine(ниска2);

Резултат:

Ниска 1
Ниска 2

Писање петљи

уреди

Програмске петље представљају један од темеља програмирања. Омогућавају програму да понавља исказ или блок исказа до испуњења одређеног услова.

У C# постоје четири различита исказа за петље:

Исказ Примена
while исказ или блок исказа се извршавају док вредност услова не false. Уколико услов пре уласка у петљу има вредност false, петља се неће извршавати
do ... while вредност услова рачуна се после извршавања блока исказа, који ће се извршити барем једном
for петље са задатим бројем циклуса. Контролни исказ петље садржи и иницијалну вредност и вредност теста
foreach петља се изводи само једном за сваки члан низа.

Основни облик while петље је следећи:

while (израз == true)
{
  //искази
}

Уместо израза може се употребити само константа true, у којем случају . А do while петља има следећи облик.

do
{
  //искази
} while (израз == true);

Разлика између њих је у томе што се код do while петље осигурава најмање једно извршавање исказа, пре рачунања услова и осим тога увек се завршава тачком и зарезом (;).

Фор петља је корисна када блок исказа треба извршити одређени број пута. Њен контролни израз се састоји из троделног исказа:

for (почетни исказ; контролни израз; израз увећања)
{
  //искази
}

Први исказ је почетни (енгл. initializing statement). У њему се задају почетне вредности контролних променљивих, а могу се и декларисати. Други исказ је контролни (енгл. test expression). Он се израчунава пре сваког циклуса петље. Трећи је исказ увећања (енгл. increment expression), у коме се најчешће мења вредност контролне променљиве.

Форич петља се користи за обраду елемената низа. У контролисаном изразу мора бити јединствена променљива чији тип одговара елементима низа, којој се при сваком проласком кроз петљу додељује вредност једног од елемената низа и тако од првог до последњег елемента.

foreach (тип променљиве in низ)
{
  //искази
}

Променљива која се декларише у контролном изразу може се само читати, не може се употребити за мењања вредсности елемента низа, што ограничава употребљивост овог типа петље. Пример:

int [] низ = new int [3] {10, 20, 30};
foreach (int број in низ)
{
  Console.WriteLine(број);
}

У оквиру сва четири типа петљи могу се користити два специјална исказа:

  • исказ continue који тренутно зауставља петљу и враћа извршавање програма на почетак петље, тако да се сви искази након овог исказа који постоје до краја петље се игноришу. Петља наставља да се извршава све док је контролни исказ тачан
  • исказ break, који зауставља петљу и програм наставља да извршава исказ након петље.

Контролни искази

уреди

Уобичајено је да програм извршава исказе редом. Већина језика располаже методама којим се управља током програма, испитивањем одређених услова и у зависности од резултата одлучује о томе шта ће се извршити.

Условни исказ - if

уреди

Контролни исказ if може да испитује само логичке услове смештене у заграде. Иза услова који може бити тачан или нетачан следи исказ, који може бити смештен и у сложен израз између витичастих заграда. Помоћу резервисане речи else може се увести исказ или блок исказа који се извршавају ако је вредност услова false. Конструкцијом else if може се проверити више услова, а број исказа који се помоћу њих може везати у ланац није ограничен:

if (условни израз1)
{
  //исказ
}
else if (условни израз2)
{
  //исказ
}
else if (условни израз2)
{
  //исказ
}
else
  //исказ

Последњи else у ланцу нема одговарајуће if. Овај последњи else није обавезан, али ако се употреби, мора бити последњи у ланцу. Вредност свих услова мора бити логичка, вредности тачан или нетачан. Програм испитује редом сваки услов док не добије резултат тачно, након чега ће се извршити дати исказ или блок исказа и остатак ланца се игнорише, чак иако је неки од преосталих услова тачан. Ако баш ниједан услов није тачан, извршиће се исказ који долази после else. У сваком случају, увек се извршава само један исказ или блок исказа у ланцу, док се остали игноришу.

Условни исказ switch

уреди

Ако се у оквиру ланца услова испитују целобројне вредности, може се искористити исказ switch. Он израчунава израз и упућује програм на блок исказа који одговара резултату:

Приликом коришћења исказа switch треба поштовати следећа правила:

  • вредност контролног израза мора да буде целобројна, односно типа bool, int, long или short int
  • за обележавање блокови кода се користи резервисана реч case, а вредност иза ње мора бити константа истог типа као и вредност у контролном израз и никако не може да стоји променљива. Блок иза исказа case се извршава ако се задата вредност подудара са резултатом услова
  • исказ case увек се смешта у витичасте заграде
  • сваки блок case мора да се заврши исказом који ће преусмерити програм ка другом исказу. Тај исказ могу бити искази break, goto, return или continue, овај последњи само у случају да се исказ switch налази у оквиру неке петље.

Постоји и могућност да уколико се резултат не поклапа ни са једном задатом вредношћу у блоку switch изврши посебан случај default.

switch(израз)
{
  case 1:
    искази;
    break;
  case 2:
    искази;
    break;
  default:
    искази;
    break;
}

Референце

уреди
  1. ^ Hamilton, Naomi (1. 10. 2008). „The A-Z of Programming Languages: C#”. Computerworld. Приступљено 1. 10. 2017. 
  2. ^ Wylie Wong (2002). „Why Microsoft's C# isn't”. CNET: CBS Interactive. Приступљено 19. 10. 2017. 
  3. ^ Joy, Bill (7. 2. 2002). „Microsoft's blind spot”. cnet.com. Приступљено 12. 1. 2010. 
  4. ^ Klaus Kreft and Angelika Langer (2003). „After Java and C# - what is next?”. Приступљено 29. 6. 2017. 
  5. ^ Klaus Kreft; Angelika Langer (3. 7. 2003). „After Java and C# - what is next?”. artima.com. Приступљено 12. 10. 2017. 
  6. ^ Osborn, John (1. 8. 2000). „Deep Inside C#: An Interview with Microsoft Chief Architect Anders Hejlsberg”. O'Reilly Media. Приступљено 29. 11. 2017. 
  7. ^ „Generics (C# Programming Guide)”. Microsoft. 18. 3. 2022. Приступљено 21. 3. 2011. 
  8. ^ Mercer, Ian (15. 4. 2010). „Why functional programming and LINQ is often better than procedural code”. abodit.com. Архивирано из оригинала 11. 07. 2011. г. Приступљено 27. 10. 2017. 
  9. ^ Karli Watson (2002). „Od pocetka..C#” (PDF). CET Computer Equipment and Trade. Приступљено 28. 11. 2017. 
  10. ^ Karli Watson (2002). „Od pocetka..C#” (PDF). CET Computer Equipment and Trade. Приступљено 28. 11. 2017. 
  11. ^ Кључне речи језика C# Архивирано на сајту Wayback Machine (8. април 2008) — са сајта Мајкрософта
  12. ^ Типови података језика C# — са сајта Мајкрософта

Види још

уреди

Спољашње везе

уреди