4. Advanced C# || C# 10 Flashcards
What is a delegate?
A delegate is an object that knows how to call a method.
Delegates type specifically defines methods return type and its parameters types.
delegate int Transformer (int x);
Now this Transformer is compatible with any method which return type is int and has one parameter of type int. Such as:int Square (int x) { return x*x;}
Also Transformer now can be used as a type, and following is possible:Transformer t = Square;
var x = t(3);
// 9;
What is a higher-order function?
A function that takes a function as a parameter. Example would be a delegate as param or return type
What is a multicast delegate?
it a delegate that can reference a list of target methods.
~~~
SomeDelegate d = SomeMethod1;
d += SomeMethod2;
~~~
Invoking d will now invoke SomeMethod1 and SomeMethod2 in the same order they were added.
Note: delegates are immutable so every time the += or -= are performed, new delegate is created an assigned to the same variable.
What are Func and Action delegates?
These are generic delegates that work for methods of any return type and any number of arguments.
In and out annotations indicate variance:delegate TResult Func <out TResult>();
delegate TResult Func <in T, out TResult> (T arg);
Difference between Func
and Action
delegates is that Action
delegate does not have a return type
Since we are able to implement the same delegate functionality with interface, which is better and why?
Delegates should be used for simplier syntax.
Also, for interface to be able to implement this these conditions should be true:
- The interface defines only a single method
- Multicast capability is needed
- The subscriber needs to implement the interface multiple times
When multicast delegates are considered equal?
When they reference the same methods in the same order
What is a broadcaster and subscriber?
Broadcaster is a type that contains a delegate field. The broadcaster decides when to broadcast by invoking the delegate
The subscribers are the method target recipients. A subscriber does not interfere with other subscribers.
What are events?
An event is a construct that exposes just the subset of delegate features required for the subscriber/broadcaster model. The main purpose of events is to prevent subscribers from interfering with one another.
Simpliest way to declare an event is to put the ‘event’ keyword in front of a delegate member:
// Delegate definitionpublic delegate void MyDelegate(decimal x, decimal y);
// Event declarationpublic event MyDelegate MyEvent;
For the event to be able to call any method, it needs to be added += or removed -= from the event’s method list. Keep in mind that those methods should still keep the suggested signature (following how delegates work).
The event will be triggered :MyEvent (1.1m, 2.2m);
Then all subscribed methods will be called in order they subscribed
Compare multicast delegate and event
Both are really similar in a way how they have a subscribed method list. When triggered they call a list of linked methods one by one.
**Differences: **
1. The main difference between an event and a delegate is that an event has an access level, which is typically set to protected or private, whereas a delegate does not. Events are not directly accessible to other classes, and other classes are not able to reassign it, or add or remove methods from its invocation list. Events can only be raised by the code in the same class, making it harder for other classes to accidentally modify the event’s invocation list.
2. Additionally, when you declare an event, the compiler automatically creates a private field which will store the delegate instance and provides add and remove methods which are used to handle += and -= operators respectively. These methods are thread-safe and make sure that multiple threads can’t modify the event’s invocation list simultaneously.
3. While both events and delegates use the += and -= operators for adding and removing subscribers, the way that the C# compiler handles these operators is different for events and delegates. When you use the += operator with a delegate, you are actually adding a new method to the delegate’s invocation list. On the other hand, when you use the += operator with an event, you are actually calling the add_PriceChanged method created by the compiler. This method is responsible for adding the new subscriber method to the event’s invocation list. This difference in how the += and -= operators are handled is important because events provide additional safeguards to ensure that the event’s invocation list is modified correctly, ensuring that multiple threads can’t modify the event’s invocation list simultaneously. In the case of a delegate, adding or removing methods from the invocation list is not thread-safe and might cause problems in multi-threaded environments.
What is a standart event pattern?
It is used to provide consistency across library and user code. The core is System.EventArgs predefined class with no members.
Pattern has three rules:
1. It must have void return type.
2. It must accept 2 arguments:
a) First of type object - indicates the event broadcaster
b) Second of subclass of EventArgs - contains the extra information to convey
3. Its name must end with EventHandler;
4. Requires that you write a protected virtual method that fires the event. It must be prefixed with ‘On’ and accept a single EventArgs argument:
~~~
protected virtual void OnPriceChanged(PriceChangedEventArgs e){
PriceChanged?.Invoke(this, e)
}
~~~
What are the event accesors? When is it useful to set custom accessors?
The accesors are the implementation of += and -= operators done by the compiler implicitly converting the event declaration.
It is converted to
1. private delegate field
2. public pair of event accessor functions that starts with add_eventName and remove_eventName
By setting explicit event accessors you can apply more complex strategies to the storage and access of underlying delegate.
Scenarios when this is useful:
a) When the event accessors are merely relays for another class that is broadcasting the event
b) When the class exposes many events for which most of the time very few subscribers exist, such as a Windows control. In such cases it is better to store the subscribers delegate instances in a dictionary because dictionary will contain less storage overhead than dozens of null delegate field references.
c) when explicitly implementing a interface that declares an event
What is a lambda expression?
(parameters) => expression-or-statement-block;
Lambda expression is an unnamed method written in place of a delegate instance. The compiler immediately converts it to either:
1. a delegate instance
2. An expression tree of type Expression<TDelegate>
representing the code inside the lamda expression in traversable object model.
Lambda expressions are used most commonly with Func and Action delegates
~~~
Func<string, string, int> totalLength = (s1, s2) => s1.Length + s2.Length;
int total = totalLength (“Labas”, “vakaras”);
~~~
What is a captured variable?
Outer variables referenced by the lambda expresssions are called captured variables:
~~~
var factor = 2;
var multiplier = x => x * factor;
Console.Log(multiplier(3));
~~~
factor here is a captured variable.
Also, when a variable has been captured it’s lifetime is prolonged to be as of delegate which captured it
Why would we use static keyword on delegates?
This can be useful in micro-optimization scenarios to prevent unintentional memory allocation as it cannot reach local variables or it will throw compile error.
However if the labda doesnt capture variables the compiler will reuse a single cached instance across the life of application
Which is better to use (has more advantages in comparison): local method or lambda expression?
Local method.
Here’s why:
1. They can be recurssive (call themselves) without ugly hacks
2. They avoid the clutter of specifying a delegate
3. They incur slightly less overhead
Local methods are slightly more efficient because they avoid the indirection of a delegate.
They can also access local variables of containing method without some extra compiler work.
What is an anonymous method?
Anonymous method is like lambda expression but lacks:
1. Implicitly typed parameters
2. Expression syntax
3. The ability to compile to an expression tree by assigning to Expression<T>
As the name suggests, an anonymous method is a method without a name. Anonymous methods in C# can be defined using the delegate keyword and can be assigned to a variable of delegate type.
~~~
Print print = delegate(int val) {
Console.WriteLine(“Inside Anonymous method. Value: {0}”, val);
};
print(100); ~~~
What is a try statement?
A try statement specifies a code block subject to error-handling or cleanup code.
The try statement must be followed by one or more catch and/or a finally block (or both). The catch statement is executed when there’s an error in try block. Finally is executed after try and catch blocks to perform cleanup regardless if error was thrown or not.
Catch statement has access to an Exception object that contain information about the error
What are the benefits of catch clause?
Error handling: A catch clause allows you to handle errors that occur within the try block, so that your program can continue to run instead of crashing.
Improved debugging: By using a catch clause, you can add extra debugging information, such as logging the error message and stack trace, which can make it easier to understand what went wrong and how to fix it.
Code organization: Try-catch statements help you keep your code organized by separating the normal flow of control from the error handling code. This makes your code easier to read and understand.
Flexibility: A catch clause can catch multiple types of exceptions, which allows you to handle different types of errors in different ways if needed.
Defensive Programming: A catch block can also help in defensive programming to anticipate and manage exceptional conditions and avoid abrupt termination of program.
How can we add a special condition to catch clause?
By adding ‘when’ after the variable brackets like so:
~~~
catch (Webexception ex) when (ex.Status == Status.TimeOut)….
~~~
What is so specific about finally block?
It always gets called no matter what. The only exceptions are program crash or infinite loop somewhere else.
Most common practise is to use Dispose on an object within finally block
What is the connection between ‘using’ statement and try statement?
‘using’ statement implements IDisposable interface which when used sort of creates try-finally block. In this finally block a Dispose() method is implemented to clean up all unused resources left by previous object that needed this using statement.
Why should someone catch and exception and throw another type of exception in the same catch block?
Rethrowing a less-specific exception is something you might do when crossing a trust boundary so as not to leak technical information to potential hackers.
Lets say we cought an exceptio in catch block. How can we:
a) throw the original exception again?
b) throw new exception which is of the same type?
a) the original exception can be thrown by simply typing ‘throw’;
b) new exception of the same type will be thrown by typing “throw new SameException (“same old same”, ex);
What are the key properties of System.Exception?
- StackTrace: A string representing all the methods that are called from the origin of the exeption to the catch block;
- Message: A string with a description of the error;
- InnerException: The inner exception that caused the outer exception. This itself can have another InnerException