How can you restrict the number of instances that can be created on a class?

  • To keep a track on the number of instances created on a class, you can maintain a static counter that is incremented each time the constructor is called. By principle, the constructor is called exactly once whenever a new instance is created.
  • If the counter reaches over a limit, you can throw an Exception which breaks the instantiation.
    class MyClass2
    {
        private static int _counter = 0;
        public MyClass2()
        {
            if (_counter > 2)
            {
                throw new Exception("Instances created beyond limit");
            }
            else
            {
                ++_counter;
            }
        }

        public void ShowCounter()
        {
            Console.WriteLine($"Counter is at {_counter}");
        }
    }
    
    
    MyClass2 c;
    for (int i = 0; i < 5; i++)
    {
        c = new MyClass2();
        c.ShowCounter();
    }
    
    output:
    Counter is at 1
    Counter is at 2
    Counter is at 3
    Unhandled exception. System.Exception: Instances created beyond limit

How can you improve the performance of a c# application?

Optimizing the performance of a C# code, we can apply the following code practices:

  • Make sure we're using the correct type or data structure based on the scenario. Using an Array in place of a List whenever possible can help, because List stores data in terms of objects in a dynamic array fashion, while an Array stores in a fixed length of sequential data.
  • Use a for loop instead of a for-each loop. Because a for-each loop internally takes time to initialize and run an enumerator which is a performance overhead.
  • Use a StringBuilder while performing string manipulations, because Strings are immutable and each time a string is manipulated a new String object is created.
  • Use a struct over a class if possible, since struct is a value type which is faster than a class which is a reference type.
  • Using a variable in place of a property when the property isn't necessarily required can help improve performance - since a property is internally a variable with additional functionality (setter and getter) added, which might not be required in all the cases.

What is a factory pattern? how do you implement it?

  • Factory Method is one of the 23 design patterns.
  • It is a creational pattern, meaning it describes the best way of instantiating a class based on an input varying condition.
  • Factory method helps in deciding which instance of a class needs to be supplied based on an input condition which is resolved during runtime.
  • It helps in creating loosely-coupled applications where the choice of functionality can be switched during runtime.
  • It states that - "just define an interface or abstract class for creating an object but let the subclasses decide which class to instantiate"

Exploring Design Patterns - Factory Method

What is abstraction? What are the different ways to achieve abstraction?

  • Abstraction is one of the characteristic features of Object Oriented Programming.
  • Abstraction enforces the rule that a component "exposes only which is required for the context".
  • This ensures a proper layer of view, where the client is provided with access to those features or contents of it which are needed for the moment.
  • In C#, abstraction is achieved in two ways: by the use of abstract classes and interfaces.
  • An abstract class is a class which can't be instantiated but is extended by its sub classes which create different versions of the functionality defined in the abstract class.
  • An interface is like a contract - it only contains a template of how the component would look like, and all its sub classes must implement the same design.
  • Abstract classes are used to create base functionality with a scope for further extension, while interfaces are created to use while interacting with other components without having to use concrete types that contain functionality.

Object Oriented Programming Concepts - Abstraction

Different access modifiers in C#?

There are four access modifiers in C# which can control the access over the class members and functionalities as a part of data Encapsulation. They are:

  • public - accessible for all classes
  • private - Only accessible within the same class
  • protected - accessible within the same class, or in a class that is inherited from that class.
  • internal - only accessible within its own namespace, but not from another namespace.

How do you call an API from C#?

  • To call an API for data, we can use the built-in HttpClient that comes with the System.Net namespace.
using (HttpClient client = new HttpClient())
{
  var response = await client.GetStringAsync("http://referbruv.com");
  Console.WriteLine(response);
}
  • HttpClient implements the IDisposable interface and so can be used under a using block. But it is one of those unmanaged resources which should not be released frequently and instead be reused as much as possible.

What are Generics? How do you write a Generic method that takes two type arguments and return a value?

  • Generics introduce the concept of passing types as parameters.
  • These make it possible to design classes and methods which can be reused for all types, and the type is deferred until the class is instantiated at the client code.
  • Generics provide code-reuse, type safety and performance
  • Most common application of Generics are the Collection types (IEnumerable, List ..) which are present in the System.Collections.Generic namespace
  • One can create own generic interfaces, events, delegates or methods.
  • Some generic types might also involve constraints on the type that is being passed to the generic types.
Program p = new Program();
Console.WriteLine(p.Add<int>(5, 7));
Console.WriteLine(p.Add<double>(4.5, 8.3));
Console.WriteLine(p.Add<string>("Alice", "Bob"));

// ERROR: Operator '+' cannot be applied to operands of type 'T' and 'T'
// cast to dynamic because compiler doesn't know the type
// to overload the + operator
public T Add<T>(T a, T b)
{
    return (dynamic)a + (dynamic)b;
}

output:
12
12.8
AliceBob

When do you use a List and when do you use a Dictionary?

  • The choice of using a List or a Dictionary depends on the requirement, since both serve different purposes.
  • A List represents a dynamic linear sequence of elements, and offers index-based access along with utility methods such as Add, Remove, Count, Min, Max and so on based on the type of the objects being added to the List.
  • If the emphasis is on manipulating the sequence of elements, then List is a good choice.
  • A Dictionary represents a generic set of KeyValue pairs with each row represented by a unique Key mapped to a value.
  • Dictionary is used in cases where the emphasis is on quickly looking up for a value since a Dictionary offers constant time lookup.