Functional Programming Extension Methods, Lambda Expressions, LINQ Svetlin Nakov Technical Trainer Software University

Slides:



Advertisements
Similar presentations
Extension Methods, Anonymous Types LINQ Query Keywords, Lambda Expressions Svetlin Nakov Telerik Corporation
Advertisements

2.3 Cool features in C# academy.zariba.com 1. Lecture Content 1.Extension Methods 2.Anonymous Types 3.Delegates 4.Action and Func 5.Events 6.Lambda Expressions.
Software Quality Assurance QA Engineering, Testing, Bug Tracking, Test Automation Software University Technical Trainers SoftUni Team.
Other Types in OOP Enumerations, Structures, Generic Classes, Attributes Svetlin Nakov Technical Trainer Software University
C# Advanced Topics Methods, Classes and Objects SoftUni Team Technical Trainers Software University
Operators, Expressions, Projections, Aggregations Svetlin Nakov Telerik Corporation
Methods Writing and using methods, overloads, ref, out SoftUni Team Technical Trainers Software University
Software University Curriculum, Courses, Exams, Jobs SoftUni Team Technical Trainers Software University
Extension Methods, Lambda Expressions, LINQ Operators, Expressions, Projections, Aggregations Extension Methods, Lambda Expressions, LINQ Operators, Expressions,
Software Testing Lifecycle Exit Criteria Evaluation, Continuous Integration Ivan Yonkov Technical Trainer Software University.
Design Patterns: Structural Design Patterns
Extension Methods, Anonymous Types LINQ Query Keywords, Lambda Expressions Based on material from Telerik Corporation.
Conditional Statements Implementing Control-Flow Logic in C# SoftUni Team Technical Trainers Software University
Consuming REST Services from C# SoftUni Team Technical Trainers Software University
Loops Repeating Code Multiple Times SoftUni Team Technical Trainers Software University
Entity Framework Performance SoftUni Team Technical Trainers Software University
Methods, Arrays, Lists, Dictionaries, Strings, Classes and Objects
Svetlin Nakov Technical Trainer Software University
Build Processes and Continuous Integration Automating Build Processes Software University Technical Trainers SoftUni Team.
Delegates and Events Callback Functionality and Event-Driven Programming Svetlin Nakov Technical Trainer Software University
Multidimensional Arrays, Sets, Dictionaries Processing Matrices, Multidimensional Arrays, Dictionaries, Sets SoftUni Team Technical Trainers Software University.
Test-Driven Development Learn the "Test First" Approach to Coding SoftUni Team Technical Trainers Software University
Defining Classes Classes, Fields, Constructors, Methods, Properties SoftUni Team Technical Trainers Software University
Functions Reusable Parts of Code SoftUni Team Technical Trainers Software University
Static Members and Namespaces Static Members, Indexers, Operators, Namespaces SoftUni Team Technical Trainers Software University
Java Collections Basics Arrays, Lists, Strings, Sets, Maps Svetlin Nakov Technical Trainer Software University
Templating, Routing, lodash Extending functionality using Collections SoftUni Team Technical Trainers Software University
Graphs and Graph Algorithms Fundamentals, Terminology, Traversal, Algorithms SoftUni Team Technical Trainers Software University
Arrays, Lists, Stacks, Queues Processing Sequences of Elements SoftUni Team Technical Trainers Software University
Controllers and Markup Controllers, $scope, Markup, Directives, Expressions, Binding, Filters, Validation SoftUni Team Technical Trainers Software University.
Using SQL Connecting, Retrieving Data, Executing SQL Commands, … Svetlin Nakov Technical Trainer Software University
C# Basics Course Introduction Svetlin Nakov Technical Trainer Software University
Callback Functionality and Event-Driven Programming
Defining Classes Classes, Fields, Constructors, Methods, Properties Svetlin Nakov Technical Trainer Software University
Forms Overview, Query string, Submitting arrays, PHP & HTML, Input types, Redirecting the user Mario Peshev Technical Trainer Software.
Other Types in OOP Enumerations, Structures, Generic Classes, Attributes SoftUni Team Technical Trainers Software University
Console Input / Output Reading and Writing to the Console SoftUni Team Technical Trainers Software University
Processing JSON in.NET JSON, JSON.NET LINQ-to-JSON and JSON to XML SoftUni Team Technical Trainers Software University
Associative Arrays and Objects Associative Arrays, Objects Svetlin Nakov Technical Trainer Software University
High-Quality Programming Code Code Correctness, Readability, Maintainability Svetlin Nakov Technical Trainer Software University
Design Patterns: Structural Design Patterns General and reusable solutions to common problems in software design Software University
IAP C# 2011 Lecture 2: Delegates, Lambdas, LINQ Geza Kovacs.
Advanced C# Course Introduction SoftUni Team Technical Trainers Software University
Object-Oriented Programming Course Introduction Svetlin Nakov Technical Trainer Software University
Reflection Programming under the hood SoftUni Team Technical Trainers Software University
Mocking with Moq Tools for Easier Unit Testing SoftUni Team Technical Trainers Software University
Operators and Expressions
Mocking Unit Testing Methods with External Dependencies SoftUni Team Technical Trainers Software University
Mocking with Moq Mocking tools for easier unit testing Svetlin Nakov Technical Trainer Software University
Functional Programming Extension Methods, Lambda Expressions, LINQ SoftUni Team Technical Trainers Software University
LINQ and Lambda Expressions Telerik Software Academy LINQ Overview.
ORM Basics Repository Pattern, Models, Entity Manager Ivan Yonkov Technical Trainer Software University
Test-Driven Development Learn the "Test First" Approach to Coding Svetlin Nakov Technical Trainer Software University
Programming for Beginners Course Introduction SoftUni Team Technical Trainers Software University
Sets, Dictionaries SoftUni Team Technical Trainers Software University
Advanced Tree Structures Binary Trees, AVL Tree, Red-Black Tree, B-Trees, Heaps SoftUni Team Technical Trainers Software University
Chapter 11.  Large amounts of data are often stored in a database—an organized collection of data.  A database management system (DBMS) provides mechanisms.
Functional Programming Data Aggregation and Nested Queries Ivan Yonkov Technical Trainer Software University
First Steps in PHP Creating Very Simple PHP Scripts SoftUni Team Technical Trainers Software University
Inheritance Class Hierarchies SoftUni Team Technical Trainers Software University
Stacks and Queues Processing Sequences of Elements SoftUni Team Technical Trainers Software University
Generics SoftUni Team Technical Trainers Software University
Functional Programming
C# Basic Syntax, Visual Studio, Console Input / Output
Introduction to Entity Framework
Repeating Code Multiple Times
Arrays, Lists, Stacks, Queues
Functional Programming
Processing Variable-Length Sequences of Elements
Functional Programming and Stream API
Presentation transcript:

Functional Programming Extension Methods, Lambda Expressions, LINQ Svetlin Nakov Technical Trainer Software University

2 1.Functional Programming Paradigms 2.Extension Methods 3.Anonymous Types 4.Lambda Expressions 5.LINQ Queries 6.Dynamic Type Table of Contents

Functional Programming Paradigms, Concepts, Languages

4  Functional programming is a programming paradigm  Uses computations of mathematical functions to build programs  Declarative programming paradigm (not imperative)  Uses first-class functions, higher-order functions, lambda functions, anonymous functions, closures, etc.  Pure-functional languages (no variables and loops): Haskell  Almost-functional: Clojure, Lisp, Scheme, Scala, F#, JavaScript  Imperative with functional support: C#, Python, Ruby, PHP, Java  Non-functional: C, Pascal, the old versions of C#, Java, C++, PHP What is Functional Programming?

5  First-class functions  Variables holding functions as a value (delegates in C#)  Higher-order functions  Functions taking other functions as input (LINQ extensions in C#)  Оr returning a function as output  Closures  Nested functions hold (close) persistent state in their outer scope  Allow creating objects with private fields in functional languages Functions in Functional Programming

6  Anonymous functions  Functions without names (delegates in C#), e.g.  Lambda functions  Anonymous functions that take parameters and return value  Example: Functions in Functional Programming (2) var f = function(a, b) { return a+b; } f(3, 5)  8 (x, y) => x*x + y*y

7  Functional programming  Program by invoking sequences of functions  Example in JavaScript: Functional vs. Imperative Programming  Imperative programming  Describe the algorithm by programming constructs  Example in JavaScript: var arr = [2, 3, 1, 8, 5]; arr.forEach( function(element, index) { function(element, index) { console.log(element); console.log(element); }); var arr = [2, 3, 1, 8, 5]; for (var i in arr) { console.log(arr[i]); console.log(arr[i]);}

Extension Methods

 Once a type is defined and compiled into an assembly its definition is, more or less, final  The only way to update, remove or add new members is to recode and recompile the code  Extension methods allow existing compiled types to gain new functionality  Without recompilation  Without touching the original assembly 9

Defining Extension Methods  Extension methods  Defined in a static class  Defined as static  Use the this keyword before its first argument to specify the class to be extended  Extension methods are "attached" to the extended class  Can also be called statically through the defining static class 10

Extension Methods – Examples 11 public static class Extensions { public static int WordCount(this string str) public static int WordCount(this string str) { return str.Split(new char[] { ' ', '.', '?' }, return str.Split(new char[] { ' ', '.', '?' }, StringSplitOptions.RemoveEmptyEntries).Length; StringSplitOptions.RemoveEmptyEntries).Length; }}… static void Main() { string s = "Hello Extension Methods"; string s = "Hello Extension Methods"; int i = s.WordCount(); int i = s.WordCount(); Console.WriteLine(i); Console.WriteLine(i);}

Extension Methods – Examples (2) 12 public static void IncreaseWidth(this IList list, int amount) { for (int i = 0; i < list.Count; i++) for (int i = 0; i < list.Count; i++) { list[i] += amount; list[i] += amount; }}… static void Main() { List ints = List ints = new List { 1, 2, 3, 4, 5 }; new List { 1, 2, 3, 4, 5 }; ints.IncreaseWidth(5); // 6, 7, 8, 9, 10 ints.IncreaseWidth(5); // 6, 7, 8, 9, 10}

Extension Methods Live Demo

Anonymous Types

 Anonymous types  Encapsulate a set of read-only properties and their value into a single object  No need to explicitly define a type first  To define an anonymous type  Use of the new var keyword in conjunction with the object initialization syntax 15 var point = new { X = 3, Y = 5 };

Anonymous Types – Example  At compile time, the C# compiler will autogenerate an uniquely named class  The class name is not visible from C#  Using implicit typing ( var keyword) is mandatory 16 // Use an anonymous type representing a car var myCar = new { Color = "Red", Brand = "BMW", Speed = 180 }; new { Color = "Red", Brand = "BMW", Speed = 180 }; Console.WriteLine("My car is a {0} {1}.", myCar.Color, myCar.Brand); myCar.Color, myCar.Brand);

Anonymous Types – Properties System.Object  Anonymous types are reference types directly derived from System.Object  Have overridden version of Equals(), GetHashCode(), and ToString()  Do not have == and != operators overloaded 17 var p = new { X = 3, Y = 5 }; var q = new { X = 3, Y = 5 }; Console.WriteLine(p == q); // false Console.WriteLine(p.Equals(q)); // true

Arrays of Anonymous Types  You can define and use arrays of anonymous types through the following syntax: 18 var arr = new[] { new { X = 3, Y = 5 }, new { X = 3, Y = 5 }, new { X = 1, Y = 2 }, new { X = 1, Y = 2 }, new { X = 0, Y = 7 } }; new { X = 0, Y = 7 } }; foreach (var item in arr) { Console.WriteLine("({0}, {1})", Console.WriteLine("({0}, {1})", item.X, item.Y); item.X, item.Y);}

Anonymous Types Live Demo

Lambda Expressions

21  A lambda expression is an anonymous function containing expressions and statements  Used to create delegates or expression tree types  Lambda expressions =>  Use the lambda operator =>  Read as "goes to"  The left side specifies the input parameters  The right side holds the expression or statement Lambda Expressions

22  Usually used with collection extension methods like FindAll() and RemoveAll() Lambda Expressions – Examples List list = new List () { 1, 2, 3, 4 }; List evenNumbers = list.FindAll(x => (x % 2) == 0); foreach (var num in evenNumbers) { Console.Write("{0} ", num); Console.Write("{0} ", num);}Console.WriteLine(); // 2 4 list.RemoveAll(x => x > 3); // 1 2 3

23 Sorting with Lambda Expression var pets = new Pet[] { new Pet { Name="Sharo", Age=8 }, new Pet { Name="Sharo", Age=8 }, new Pet { Name="Rex", Age=4 }, new Pet { Name="Rex", Age=4 }, new Pet { Name="Strela", Age=1 }, new Pet { Name="Strela", Age=1 }, new Pet { Name="Bora", Age=3 } new Pet { Name="Bora", Age=3 }}; var sortedPets = pets.OrderBy(pet => pet.Age); foreach (Pet pet in sortedPets) { Console.WriteLine("{0} -> {1}", pet.Name, pet.Age); Console.WriteLine("{0} -> {1}", pet.Name, pet.Age);}

24  Lambda code expressions: Lambda Code Expressions List list = new List () { 20, 1, 4, 8, 9, 44 }; // Process each argument with code statements List evenNumbers = list.FindAll((i) => { Console.WriteLine("value of i is: {0}", i); Console.WriteLine("value of i is: {0}", i); return (i % 2) == 0; return (i % 2) == 0;}); Console.WriteLine("Here are your even numbers:"); foreach (int even in evenNumbers) Console.Write("{0}\t", even); Console.Write("{0}\t", even);

25  Lambda functions can be stored in variables of type delegate  Delegates are typed references to functions  Standard function delegates in.NET:  Func, Func, Func, … Delegates Holding Lambda Functions Func boolFunc = () => true; Func intFunc = (x) => x intFunc = (x) => x < 10; if (boolFunc() && intFunc(5)) Console.WriteLine("5 < 10"); Console.WriteLine("5 < 10");

26  Predicates are predefined delegates with the following signature  Define a way to check if an object meets some Boolean criteria  Similar to Func  Similar to Func  Used by many methods of Array and List to search for an element  For example List.FindAll(…) retrieves all elements meeting the criteria Predicates public delegate bool Predicate (T obj)

27 Predicates – ExamplePredicates – Example List towns = new List () { "Sofia", "Plovdiv", "Varna", "Sopot", "Silistra" }; List townsWithS = towns.FindAll(delegate(string town) towns.FindAll(delegate(string town) { return town.StartsWith("S"); return town.StartsWith("S"); }); }); // A short form of the above (with lambda expression) List townsWithS = towns.FindAll((town) => town.StartsWith("S")); towns.FindAll((town) => town.StartsWith("S")); foreach (string town in townsWithS) { Console.WriteLine(town); Console.WriteLine(town);}

Lambda Expressions Live Demo

29  Action – void delegate with parameter T  Func – result delegate returning TResult Action and Func Action act = (number) => { Console.WrileLine(number); } Console.WrileLine(number); } act(10); // logs 10 Func greet = (name, age) => { return "Name: " + name + "Age: " + age; return "Name: " + name + "Age: " + age;} Console.WriteLine(greet("Ivaylo", 10));

Action and Func Action and Func Live Demo

LINQ and Query Keywords

32  LINQ is a set of extensions to.NET Framework  Encompasses language-integrated query, set, and transform operations  Consistent manner to obtain and manipulate "data" in the broad sense of the term  Query expressions  Query expressions can be defined directly within the C# programming language  Used to interact with numerous data types  Converted to expression trees at compile time and evaluated at runtime (when invoked, e.g. by foreach ) LINQ Building Blocks (2)

33 LINQ to * LINQ enabled data sources LINQ to Objects Objects LINQ to XML XML LINQ enabled ADO.NET LINQ to DataSets LINQ to SQL LINQ to Entities Relational Data Others Others … C# VB.NET.NET Language-Integrated Query (LINQ)

34  Language Integrated Query (LINQ) query keywords  from – specifies data source and range variable  where – filters source elements  select – specifies the type and shape that the elements in the returned sequence  group – groups query results according to a specified key value  orderby – sorts query results in ascending or descending order LINQ and Query Keywords

35  select, from and where clauses: Query Keywords – Examples int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; var querySmallNums = from num in numbers from num in numbers where num < 5 where num < 5 select num; select num; foreach (var num in querySmallNums) { Console.Write(num.ToString() + " "); Console.Write(num.ToString() + " ");} // The result is

36  Nested queries: Query Keywords – Examples (2) string[] towns = { "Sofia", "Varna", "Pleven", "Ruse", "Bourgas" }; { "Sofia", "Varna", "Pleven", "Ruse", "Bourgas" }; var townPairs = from t1 in towns from t1 in towns from t2 in towns from t2 in towns select new { T1 = t1, T2 = t2 }; select new { T1 = t1, T2 = t2 }; foreach (var townPair in townPairs) { Console.WriteLine("({0}, {1})", Console.WriteLine("({0}, {1})", townPair.T1, townPair.T2); townPair.T1, townPair.T2);}

37  Sorting with оrderby : Query Keywords – Examples (3) string[] fruits = { "cherry", "apple", "blueberry", "banana" }; { "cherry", "apple", "blueberry", "banana" }; // Sort in ascending sort var fruitsAscending = from fruit in fruits from fruit in fruits orderby fruit orderby fruit select fruit; select fruit; foreach (string fruit in fruitsAscending) { Console.WriteLine(fruit); Console.WriteLine(fruit);}

38 Standard Query Operators – Example string[] games = {"Morrowind", "BioShock","Half Life", "The Darkness","Daxter", "System Shock 2"}; "The Darkness","Daxter", "System Shock 2"}; // Build a query expression using extension methods // granted to the Array via the Enumerable type var subset = games.Where(game => game.Length > 6). OrderBy(game => game).Select(game => game); OrderBy(game => game).Select(game => game); foreach (var game in subset) Console.WriteLine(game); Console.WriteLine(game);Console.WriteLine(); var subset = from g in games from g in games where g.Length > 6 where g.Length > 6 orderby g orderby g select g; select g;

39 Counting the Words in a String – Example string text = "Historically, the world of data …"; … string searchTerm = "data"; string[] source = text.Split( new char[] { '.', '?', '!', ' ', ';', ':', ',' }, new char[] { '.', '?', '!', ' ', ';', ':', ',' }, StringSplitOptions.RemoveEmptyEntries); StringSplitOptions.RemoveEmptyEntries); // Use ToLower() to match both "data" and "Data" var matchQuery = from word in source from word in source where word.ToLower() == searchTerm.ToLower() where word.ToLower() == searchTerm.ToLower() select word; select word; int wordCount = matchQuery.Count(); matchQuery.Count(); int wordCount = source.Where( w => w.toLower() == w => w.toLower() == searchTerm.ToLower()).Count(); searchTerm.ToLower()).Count();

40  Any kind of arrays can be used with LINQ  Can even be an untyped array of objects  Queries can be applied to arrays of custom objects  Example: Querying Arrays Book[] books = { new Book { Title="LINQ in Action" }, new Book { Title="LINQ in Action" }, new Book { Title="LINQ for Fun" }, new Book { Title="LINQ for Fun" }, new Book { Title="Extreme LINQ" } }; new Book { Title="Extreme LINQ" } }; var titles = books.Where(book => book.Title.Contains("Action")).Where(book => book.Title.Contains("Action")).Select(book => book.Title);.Select(book => book.Title); var titles = from b in books from b in books where b.Title.Contains("Action") where b.Title.Contains("Action") select b.Title; select b.Title;

41  The previous example can be adapted to work with a generic list  List, LinkedList, Queue, Stack, HashSet, etc. Querying Generic Lists List books = new List () { new Book { Title="LINQ in Action" }, new Book { Title="LINQ in Action" }, new Book { Title="LINQ for Fun" }, new Book { Title="LINQ for Fun" }, new Book { Title="Extreme LINQ" } }; new Book { Title="Extreme LINQ" } }; var titles = books.Where(book => book.Title.Contains("Action")).Where(book => book.Title.Contains("Action")).Select(book => book.Title);.Select(book => book.Title);

42  Although System.String may not be perceived as a collection at first sight  It is actually a collection, because it implements IEnumerable  String objects can be queried with LINQ to Objects, like any other collection Querying Strings var count = "Non-letter characters in this string: 8".Where(c => !Char.IsLetter(c)).Where(c => !Char.IsLetter(c)).Count();.Count();Console.WriteLine(count); // The result is: 8 var count = (from c in "Non-letter…" (from c in "Non-letter…" where !Char.IsLetter(c) where !Char.IsLetter(c) select c).Count(); select c).Count();

43  Where()  Searches by given condition  First() / FirstOrDefault()  Gets the first matched element  Last() / LastOrDefault()  Gets the last matched element  Select() / Cast()  Makes projection (conversion) to another type  OrderBy() / ThenBy() / OrderByDescending()  Orders a collection LINQ: Operations

44  Any()  Checks if any element matches a condition  All()  Checks if all elements match a condition  ToArray()/ToList()/AsEnumerable()  Converts the collection type  Reverse()  Reverses a collection LINQ: Operations (2)

45  Average()  Calculates the average value of a collection  Count()  Counts the elements in a collection  Max()  Determines the maximum value in a collection  Sum()  Sums the values in a collection LINQ Aggregation Methods

46  Count( )  Max() LINQ Aggregation Methods – Examples double[] temperatures = {28.0, 19.5, 32.3, 33.6, 26.5, 29.7}; {28.0, 19.5, 32.3, 33.6, 26.5, 29.7}; int highTempCount = temperatures.Count(p => p > 30); Console.WriteLine(highTempCount); // The result is: 2 double[] temperatures = {28.0, 19.5, 32.3, 33.6, 26.5, 29.7}; {28.0, 19.5, 32.3, 33.6, 26.5, 29.7}; double maxTemp = temperatures.Max(); Console.WriteLine(maxTemp); // The result is: 33.6 var highTemp = (from p in temperatures (from p in temperatures where p > 30 where p > 30 select p).Count(); select p).Count(); var highTemp = (from p in temperatures (from p in temperatures select p).Max(); select p).Max();

47  AsParallel() – enables the use of parallel threads  Called right before the query execution  Improves the performance when dealing with heavy operations  Can be slower than non-parallel on small number of elements Parallel Queries const int m = 1000; int[] array = Enumerable.Range(0, 1000).ToArray(); int sum = 0; for (int i = 0; i < m; i++) { sum = array.AsParallel().Sum(); sum = array.AsParallel().Sum();}

LINQ Query Keywords Live Demo

Dynamic Type

50  The dynamic type is:  Defined with the dynamic keyword  Can hold anything (numbers, strings, objects, functions, etc.)  Evaluated at runtime (when invoked)  Examples: Dynamic Type dynamic dyn = 5; dyn = "Some text"; dyn = new Student(); dyn = new[] { 5, 8, 10 }; dyn = (Func ) double.Parse;

51  In C# we have object and dynamic data types  C# objects ( System.Object instances)  Can hold any C# data, e.g. numbers, strings, arrays, methods  Strongly typed, need casting: int value = (int) obj;  C# dynamic objects  Can hold any C# data, e.g. numbers, strings, arrays, methods  Evaluated at runtime, i.e. operations are always valid, but can fail at runtime Dynamic vs. Object

52  Dynamic objects always compile, but could fail at runtime Using Dynamic Types dynamic a = 5; // a holds int value dynamic b = 2.5; // holds double value dynamic c = ; // evaluated to 7.5 (double) at runtime dynamic h = "hello"; dynamic w = "world"; dynamic str = h + w; // evaluated to string at runtime dynamic incorrect = str + a; // runtime error! dynamic x = str / 10; // runtime error!

53  ExpandoObject is a dynamic object  Its members can be dynamically added / removed at runtime  Part of System.Dynamic namespace ExpandoObject dynamic contact = new ExpandoObject(); contact.Name = "Asen"; contact.Age = 29; contact.IncrementAge = (Action)(() => { contact.Age++; }); contact.IncrementAge(); Console.WriteLine("Hi, I'm {0} and I'm {1} years old.", contact.Name, contact.Age); contact.Name, contact.Age);

Dynamic TypeDynamic Type Live Demo

55  Extension methods extend the functionality of existing types  Anonymous types are type-less objects with a set of read-only properties  Lambda expressions are anonymous functions used with delegates  LINQ is a set of extension methods for working with collections  Dynamic type objects can contain everything  Evaluated at runtime Summary

? ? ? ? ? ? ? ? ? Functional Programming

License  This course (slides, examples, demos, videos, homework, etc.) is licensed under the "Creative Commons Attribution- NonCommercial-ShareAlike 4.0 International" licenseCreative Commons Attribution- NonCommercial-ShareAlike 4.0 International 57  Attribution: this work may contain portions from  "Fundamentals of Computer Programming with C#" book by Svetlin Nakov & Co. under CC-BY-SA licenseFundamentals of Computer Programming with C#CC-BY-SA  "OOP" course by Telerik Academy under CC-BY-NC-SA licenseOOPCC-BY-NC-SA

SoftUni Diamond Partners

Free Software University  Software University Foundation – softuni.orgsoftuni.org  Software University – High-Quality Education, Profession and Job for Software Developers  softuni.bg softuni.bg  Software Facebook  facebook.com/SoftwareUniversity facebook.com/SoftwareUniversity  Software YouTube  youtube.com/SoftwareUniversity youtube.com/SoftwareUniversity  Software University Forums – forum.softuni.bgforum.softuni.bg