← Academy Blog

Training marathon 2022

Translated into:

Embarking on our Binary Studio Academy 2022 .NET entrance test prep marathon! Weekly blog posts featuring test-like questions, explanations.

  • [.NET] What type should return this method?
    public static {ReturnType} GetNums()
    {
        var number = 0;
        while (true)
        {
            if (number > 5)
                yield break;
            yield return number++;
        }
    }

    a) void
    b) IEnumerable<int>
    c) List<int>
    d) int
    e) object

    Expand the correct answer with an explanation

    This method uses two special keywords yield break and yield return. The method in which such keywords are used is called an iterator.

    The iterator can be named (as in our case) or unnamed. An unnamed iterator is declared for the class by defining the GetEnumerator() method. In this case, instances of this class can be used directly in foreach or linq operations.

    The difference between an iterator and a regular method is that the method returns a single value with return, and the iterator returns several (or none at all). An iterator will return as many values as the yield return is called. The yield return call can be written several times in a row or, as in the task, use a loop. The yield break keyword means that no more elements do need to be returned, even if the more yield return follow. Stopping an iterator using a yield break is optional. For example, we can rewrite the code from the task like this:

    while (number < 5)
    {
        yield return number++;
    }

    Also interesting is the interception of errors in the iterator. The yield keyword cannot be used inside a try-catch block. Instead, you must first get the value to return, and only then call the yield, for example:

    foreach (var item in data)
    {
        try
        {
            result = PrepareData(item);
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine(ex.Message);
            continue;
        }
        yield return result;
    }

    The previous paragraph already mentioned where you can use the result that the iterator returns – in the foreach construction and for linq operations. Therefore, the value returned by the iterator must be an IEnumerable interface. Typification for IEnumerable must correspond to the type that returns by yield return. УIn our case it is IEnumerable<int>.

    Correct answer: b) IEnumerable<int>.

  • [.NET] Which line execution will cause an error?
    namespace BSA2021
    {
      class Program
      {
        static void Main()
        {
          var array = new string[] { "Welcome", "to", "Binary", "Studio", "Academy" };
    
          var a = array[..0];
          var b = array[2..^0];
          var c = array[^0];
        }
      }
    }
    

    a) 9
    b) 10
    c) 11
    d) No runtime errors

    Expand the correct answer with an explanation

    The task contains a small program that consists of an array of strings and actions on this array. Array actions are performed using indexes and ranges. Consider them in more detail:

    The index indicates the ordinal place of an element in the sequence. The index can be specified as either counting from the beginning of the sequence or from its end. In the first case, the index of the first element is 0, the second – 1, the third – 2, and so on. The last element has the index array.Length - 1. A special operator ^ is used to subtract an element from the end of the sequence. The last element will have the index ^1, the penultimate – ^2, and the first – ^array.Length. The index written as ^0 will correspond to the length of the array.

    The range specifies some part of the sequence bounded by two indexes. The .. operator is used to determine the range. The index of the beginning of the range is specified on the left of the operator, and the end – on the right. An element with an index corresponding to the beginning of the range is included in the range. And the element with the end index – no. In the range it is possible not to specify the index of the beginning and the end, then the initial index will be considered as 0, and the final as ^0.

    Now let's look at the execution of the program. On the seventh line, an array of lines of five elements is created correctly. On the 9th line, we take a range that starts with the first element and ends with the same first element, ie the variable a will contain an empty array of strings. On line 10 we take the range from the third to the last element, ie the variable b contains {"Binary", "Studio", "Academy" }. The 11th line has an assignment to a variable of the only one element from the array, which is on position ^0, in other words on position array.Length. Here we have an executing error IndexOutOfRangeException.

    Correct answer: b) Line 11.

  • [.NET] IDOR prevention tool (don’t be afraid of the name, the task itself is fun)Weekly Challenge

    Intro

    There is a vulnerability called insecure direct object reference (IDOR) in cybersecurity. In simple words, it’s the vulnerability when a user can access data they actually aren’t supposed to access. Usually, it happens when an application shows identifiers of internal objects in a simple form. For example, https://medium.com/@elon/posts/82048f77 or even just https://medium.com/@elon/posts/1

    Let’s imagine that it is your post by this link. If you are curious enough, you’d probably try to substitute some symbols in the GUID value in the first case or 1 with 2 in the second case to see what’ll happen.

    On the other hand, there can be an endpoint like this: https://medium.com/@elon/posts/PII6xnIiNeyv. In this case, you have no idea what value to use instead of that long ID to try your luck.

    But as a programmer, you might assume that it’s not just random letters and digits. And you will be right. Actually, it’s an encrypted GUID value.

    Task

    Create a simple application (Web API) to integrate this encryption/decryption. Use the following classes:

    Model:

    public class Resource
    {
        public Guid Id { get; set; }
        public string Name { get; set; }
    }

    Service:

    public class ResourceService
    {
        private static readonly List<Resource> Resources = new();
    
        public Guid Add(string name)
        {
            var resource = new Resource
            {
                Id = Guid.NewGuid(),
                Name = name
            };
    
            Resources.Add(resource);
            return resource.Id;
        }
    
        public Resource Get(Guid id)
        {
            var resource = Resources.FirstOrDefault(x => x.Id == id);
            return resource;
        }
    }

    Controller:

    [Route("api/[controller]")]
    [ApiController]
    public class ResourcesController : ControllerBase
    {
        private ResourceService _resourceService;
    
        public ResourcesController()
        {
            _resourceService = new ResourceService();
        }
    
        [HttpGet("{id}")]
        public Resource Get(Guid id)
        {
            return _resourceService.Get(id);
        }
    
        [HttpPost]
        public Guid Post([FromBody] string name)
        {
            return _resourceService.Add(name);
        }
    }

    If you create a simple ASP.NET Core Web API application and use these classes, you’ll have two endpoints for adding and retrieving the resource. The main catch here is that you need to update some code to comply with these requirements:

    • When you create a new resource, you need to get the id of that newly created resource in the encrypted form (not a plan GUID):
      • POST-request: /api/resource with body: "My new resource's name"
      • Response: PII6xnIiNeyv-Vxy
    • When you retrieve the resource by its id, you need to pass it in the encrypted form
      • GET-request: /api/resource/PII6xnIiNeyv-Vxy
      • Response:
    {
      "id": "82048f77-9995-4287-bc0d-471ca3c394b3",
      "name": "My new resource's name"
    }

    There are multiple ways to do this task:

    1. Plain and simple (encrypt and decrypt in every controller)
    2. Using ASP.NET Core middleware
    3. Using ASP.NET Core filters
    4. Custom JSON converters
    5. I’m pretty sure there are others

    Some of those may seem tricky, so you try to move one by one. It’s ok if you use just the first approach, but it’s an excellent opportunity to learn a lot in the ASP.NET Core while trying other ones.

    Feel free to use any kind of encryption.

    Expand the correct answer with an explanation
  • [.NET] What will be the result of executing this code?
    class Program
    {
        static void Main(string[] args)
        {
            First first = new Second("some item");
            First another = new Third();
        }
    }
    class First
    {
        public First()
        {
            Console.WriteLine("First created");
        }
    }
    class Second : First
    {
        private Second()
        {
            Console.WriteLine("Second created");
        }
        public Second(string item)
        {
            Console.WriteLine("Second created with Item: {0}",  item);
        }
    }
    class Third : Second
    {
        public Third()
        {
            Console.WriteLine("Third created");
        }
    }

    a) First createdSecond created with Item: some itemFirst createdThird created
    b) Compilation error
    c) Second created with Item: some itemThird created
    d) Runtime error

    Expand the correct answer with an explanation

    Given in the task program is built from three classes and from the call of the constructors of these classes in Main(). The inheritance mechanism is used for classes and the following hierarchy is defined: from the base class First inherits the class Second, which, in turn, has a descendant – the class Third. When we create an instance of a class that has a parent class, the parent class constructor is called first. By default, a constructor without parameters will be called for the parent class. The base() keyword is used to explicitly call the required constructor.

    The First class has a single constructor without parameters, which prints the string "First created" in the console.

    The Second class has two constructors. One of them has no parameters and prints the string "Second created", and its access level is defined as private, so it is only available for calling "inside" this class. Another constructor has an item parameter and prints the message "Second created with Item: {0}". Both of these constructors implicitly call the First() constructor.

    The Third class has a single parameterless constructor that prints "Third created" in the console. However, since there is no explicit call to the batik constructor with parameters, the private constructor Second() will be called. This will cause a CS0122 compilation error.

    Correct answer: b) Compilation error.

  • [.NET] Create a Web API application with a static in-memory database (meaning you should have one instance of this database throughout the whole application) with 20 elements max. An element must have the following fields - Id(unique), Name and CreationDate. Other fields are up to you.Weekly Challenge

    Web API should allow users to do the following:

    1. Update an element in the database using Id
    2. Add an element to the database. Keep in mind that we have a maximum of 20 elements in our database.
    3. Get a new data structure which will consist of two lists and a field containing a date. The structure should be built like this: user sends a date to the endpoint and using this date we split our list into two - first one with elements created before this date and the second one with elements created after. Date field should contain the date that was sent by a user.
    4. Delete an element from the list by Id
    Expand the correct answer with an explanation
  • [.NET] What will this code display?
    namespace BSA2021
    {
        struct Point
        {
            public int X;
            public int Y;
        }
    
        class Program
        {
            static void Main()
            {
                CreatePoint(out Point point);
                ResetPoint(in point);
                IncreasePoint(ref point);
    
                Console.WriteLine($"({point.X};{point.Y})");
            }
    
            static void ResetPoint(in Point point)
            {
                point.X = 1;
                point.Y = 1;
            }
    
            static void CreatePoint(out Point point)
            {
                point.X = 2;
                point.Y = 2;
            }
    
            static void IncreasePoint(ref Point point)
            {
                point.X *= 3;
                point.Y *= 3;
            }
        }
    }

    a) (3;3)
    b) (6;6)
    c) (0;0)
    d) Runtime error
    e) Compillation error

    Expand the correct answer with an explanation

    Let's consider what "consists" of the program in question. It is built from a simple structure and from calls of three methods to perform actions on this structure. The difficulty is that the structure, like int, is stored in the stack and is a value type. And also that methods of action over structure keywords (in, ref, out) that serve as modifiers of parameters are used. Without the use of these modifiers, a new copy of the variable data stored in the stack is always passed to the method. Consider in detail these modifiers:

    The ref keyword indicates that the argument is passed by reference, not by value. So any change in the value of this argument within the method will change the corresponding argument with which the method was called. Also, using this keyword requires that the variable be initialized before using it as a parameter otherwise, there will be a CS0165 compilation error.

    The out keyword also indicates that the argument is passed by reference. This argument is called the "output parameter" of the method and, unlike ref, does not require prior initialization of the parameter. Instead, within a method, the argument must be initialized within that method otherwise, a CS0177 compilation error occurs.

    In - specifies the parameter passed by the link, but within the method, it is forbidden to change it. This keyword is typically used when memory-intensive structures need to be passed inside a method. When trying to change this parameter there is a compiling error CS8332 – inability to change readonly variable. There is also a need to pre-initialize the variable passed as a parameter.

    Now let's analyze the call of each method from Main(). The first is the CreatePoint() call. Its parameter is marked as out, so the condition for initialization within the method is imposed. A structure is considered as initialized when all its fields are initialized – so there are no errors, and the point has the value of (2; 2). Next is the ResetPoint() call with the in parameter. Within this method, this parameter is assigned, so we have a CS0165 compilation error.

    Correct answer: e) compilation error.

  • [.NET] CalculatorWeekly Challenge

    Create a calculator that can be used like this:

    var result = 5.Add(10).MultiplyBy(2);
    // or
    result = new Calculator(5).Add(10).MultiplyBy(2).Equals();
    
    Console.WriteLine(result); // 30

    It may look a little bit different depending on the implementation, but the main idea is to use methods to perform operations in a chained way (calling one after another).

    • Implement 4 basic methods (detailed signature omitted for flexibility of your solutions):
      • Add()
      • Subtract()
      • MultiplyBy()
      • DivideBy()
    • Feel free to add other intricate methods to make your calculator more comprehensive.

    There are at least 2 possible ways to handle this task. But we encourage you to try others also. Use hints if stuck:

    • First hint This one implies ‘extending’ 😉 functionality of known types
    • Second hint Also, there is one that presumes diving into the topic of design patterns (especially those related to building stuff 🏗️)

    Feel free to come up with your own approaches.

    Do not forget that we’re building software for common users, that may make mistakes: enter strings instead of numbers, divide by 0, and so on. Allow users to use not only integers, but also float numbers. Try to handle as many edge cases as possible to stabilize your implementation.

    Expand the correct answer with an explanation
  • [.NET] Which of the catch blocks will be involved as a result of this code execution?
    static void Recursive()
    {
        Recursive();
    }
    
    try
    {
        Recursive();
    }
    catch (InsufficientMemoryException)
    {
        // block 1
        throw;
    }
    catch (OutOfMemoryException)
    {
        // block 2
        throw;
    }
    catch (StackOverflowException)
    {
        // block 3
        throw;
    }
    catch (Exception)
    {
        // block 4
        throw;
    }

    a) block 1
    b) block 2
    c) block 3
    d) block 4
    e) no block will be involved

    Expand the correct answer with an explanation

    First of all, let's remember how try…catch construct works in the presence of several catch blocks: when an exception occurs, a consistent comparison of the catch block argument type with the error object type is performed sequentially from the top. And if the type of argument matches the type of error, or if it presents in base classes of error class - the catch block is executed. The following blocks are ignored. By the way, in catch blocks the type of argument cannot be repeated. The throw constructions in the middle catch cause the error to be "passed to a higher level", and even if there is another block after the current catch block that can intercept this error by its type, it will not be executed.

    Now let's analyze what exceptions each block is intended for:

    InsufficientMemoryException – an exception indicates that the available memory was found to be insufficient. This exception occurs only when the MemoryFailPoint object is explicitly used. Is a derived type from OutOfMemoryException.

    OutOfMemoryException – reports that there is not enough memory to continue executing the program. An exception occurs either when the maximum length value for the StringBuilder is exceeded, or when the CLR cannot allocate enough continuous memory to perform an operation (object creation, method call, etc.). This error is related to heap.

    StackOverflowException – occurs when the runtime stack overflows because it contains too many nested method calls. If this error is not explicitly thrown (through throw), it cannot be intercepted by try…catch.

    Exception – base type for all exceptions. Used to declare a catch for any error. Now let's consider what occurs in the try block: the Recursive() method is called. This method doesn’t use MemoryFailPoint and doesn’t create or modify objects, so blocks 1 and 2 will not be involved. Instead, the method produces uncontrolled recursion, which will overflow the stack and cause the StackOverflowException generated by the system. Therefore, blocks 3 and 4 will also not be involved.

    Correct answer: e) no block will be involved.

  • [.NET] In this weekly challenge, you will need to create a Web API with in-memory database (aka List of items) containing 20 items.Weekly Challenge

    An item must contain Name and CreationDate fields, everything else is up to you. Web API should allow users to retrieve data in the following representations:

    1. Get the first 5 items ordered by Name in alphabetical order;
    2. Get the first 5 items ordered by CreationDate in descending order;
    3. Get all items with Name longer than 5 characters

    P.S. Feel free to use third-party libraries to create realistic fake data or create data themed on things you are interested in P.P.S You can use Postman or some other tool to test out your application.

    Expand the correct answer with an explanation