→ Delegate
A delegate in C# is like a pointer to a method. It’s a type-safe function reference—you can use it to call methods dynamically at runtime. A Delegate is similar to a class. You can create an object of it, and then you pass in the function name as a parameter to the delegate constructor, and it is to this function the delegate will point to. A delegate is a type safe function pointer. They hold pointer (reference) to a function. The signature of the delegate must match the signature of the function, the delegate points to, otherwise you get a compile time error. This is the reason delegates are called as type safe function pointers.
How to declare a delegate:
Delegates syntax look very much similar to a method with a delegate keyword.
public delegate void HelloFunctionDelegate(string Message);
Examples:
class DelegateDemoClass
{
public static void Main()
{
// Create an object of DelegateDemo and pass in the
function
// name as the parameter to the constructor. The passed in
// function signature must match the signature of the
delegate
DelegateDemo
objDelegateDemo = new DelegateDemo(MyMethod);
// Invoke the delegate, which will invoke the method
objDelegateDemo("This is from Delegate);
}
public static void MyMethod(string myMessage)
{
Console.WriteLine(myMessage);
}
public delegate void DelegateDemo(string MyMessage);
}
Where/When to use:
A Delegate can be used in various ways depend on the requirements of the project/application. The following are the lists of areas where a delegate can be used to provide better output and enhance the performance of the application.
- Method Invocation (using delegate instance)
- Event Handling using delegate
- Callback and asynchronous implementation
- Multiple method calls using Multicast delegate
Some more details about Delegeates:
Delegates in C# are type-safe function pointers or references to methods with a specific parameter list and return type. They allow methods to be passed as parameters, stored in variables, and returned by other methods, which enables flexible and extensible programming designs such as event handling and callback methods. Delegates are particularly useful in implementing the observer pattern and designing frameworks or components that need to notify other objects about events or changes without knowing the specifics of those objects.
There are three main types of delegates in C#:
Here is an example demonstrating the use of delegates in C#:
public delegate void Operation(int num);
class Program
{
static void Main(string[] args)
{
Operation op = Double;
op(5); // Output: 10
op = Triple;
op(5); // Output: 15
// Multicast delegate
op = Double;
op += Triple; // Combines Double and Triple methods
op(5); // Output: 10 followed by 15
}
static void Double(int num)
{
Console.WriteLine($"{num} * 2 = {num * 2}");
}
static void Triple(int num)
{
Console.WriteLine($"{num} * 3 = {num * 3}");
}
}
In this example, the operation delegate is defined to point to any method that accepts an int and returns void. Initially, op is set to the Double method, demonstrating a single-cast delegate. It is then reassigned to the Triple method, and finally, it is used as a multicast delegate to call both Double and Triple methods in sequence. This demonstrates how delegates in C# provide a flexible mechanism for method invocation and can be used to implement event handlers and callbacks.
→ public override string ToString();
class WebSite
{
private string _name;
private string _url;
public string Name { get { return _name; } set { _name = value; } }
public string Url { get { return _url; } set { _url = value; } }
//Comment Ucomment this method to see output
public override string ToString()
{
return _name + " - " + _url;
}
}
static void Main()
{
WebSite web = new WebSite();
web.Name
= "Ghazi";
web.Url
= "dotnet-learning-point.blogspot.com";
Console.WriteLine(web);
}
→ Properties and Fields
Property (public members) and Fields (private members, variables, attribute). Properties expose fields. Fields should (always) be kept private to a class and accessed via get and set properties. Properties provide a level of abstraction allowing you to change the fields while not affecting the external way they are accessed by the things that use your class.
public class MyClass
{
// this is a field.
It is private to your class and stores the actual data.
private string _myField;
// this is a property.
When you access it uses the underlying field, but only exposes
// the contract that will not be affected by the
underlying field
public string MyField
{
get
{
return _myField;
}
set
{
_myField = value;
}
}
}
Unlike fields, properties are not classified as variables. Therefore, you cannot pass a property as a ref or out parameter. Properties can be marked as public, private, protected, internal, or protected internal. These access modifiers define how users of the class can access the property. The get and set accessors for the same property may have different access modifiers. For example, the get may be public to allow read-only access from outside the type, and the set may be private or protected.
A property may be declared as a static property by using the static keyword. This makes the property available to callers at any time, even if no instance of the class exists. A property may be marked as a virtual property by using the virtual keyword. This enables derived classes to override the property behavior by using the override keyword. A property overriding a virtual property can also be sealed, specifying that for derived classes it is no longer virtual. Lastly, a property can be declared abstract. This means that there is no implementation in the class, and derived classes must write their own implementation.
→ Namespace:
A namespace is designed for providing a way to keep one set of names separate from another. The class names declared in one namespace does not conflict with the same class names declared in another.
Whether or not you
explicitly declare a namespace in a C# source file, the compiler adds a default
namespace. This unnamed namespace, sometimes referred to as the global
namespace, is present in every file. Any identifier in the global namespace is
available for use in a named namespace.
Namespaces implicitly
have public access and this is not modifiable. For a discussion of the access
modifiers you can assign to elements in a namespace. It is possible to define
a namespace in two or more declarations. For example, the following example
defines two classes as part of the Namespace.Test2 namespace:
using System;
namespace Namespace.Test2
{
namespace First
{
public class myClass1
{
public static void MethodOne()
{
Console.WriteLine("This is from
Namespace.Test2.First.myClass1.MethodOne()");
}
public class myNestedClass1
{
public class myNestedClass2
{
public static void MethodOne()
{
Console.WriteLine("This method is from
Namespace.Test2.First.myClass1.myNestedClass1.myNestedClass2.MethodOne()");
}
}
}
}
}
class Program
{
static void Main(string[] args)
{
Namespace.Test2.First.myClass1.myNestedClass1.myNestedClass2.MethodOne();
//Namespace.Test2.First.myClass1.MethodOne();
Namespace.Test2.First.myClass1.MethodOne();
Console.ReadKey();
}
}
}
→ System.Object (Class)
Support all classes in the .NET Framework class hierarchy and provides low-level services to derived classes. This is the ultimate class of all classes in the .NET Framework; it is the root of the type hierarchy.
Interface types, not being classes, are not derived from object. They are all convertible to object, to be sure, because we know that at runtime the instance will be a concrete type. But interfaces only derive from other interface types, and object is not an interface type.
→ Singleton Pattern
In some situation, you need a class that has only one instance and you are also make sure that this instance can be accessed any where in you application (having global point of access). Singleton pattern can help you to achieve this goal. With the help of singleton pattern, we make sure that class have have only one object with global point of access.
Examples:
1st Version - not thread-safe
//Class my be sealed but not necessary. But it is useful for JIT to optimized the things more
//Not thread safe. Bad code! Do not use!
public sealed class MySingletonClass
{
private static MySingletonClass
singletonInstance;
private MySingletonClass()
{
}
public static MySingletonClass
SingletonInstance
{
get {
if (singletonInstance == null)
{
singletonInstance = new MySingletonClass();
}
return singletonInstance;
}
}
}
1. We make constructor private, make sure that
MySingletonClass can not be initiated directly.
2. We make MySingletonClass object through private static
MySingletonClass singletonInstance field, make sure that only this class can be
initialize its own constructor.
3. Provide SingletonInstance property as Public to get
singletonInstance out side this class. It can be access when a user call this
property and it initialize our MySingletonClass object. It also called lazy
initializing (initializing on demand).
4. In our SingletonInstance property's get accessor's we are
checking singletonInstance value. Weather it is null or have a value. If it is
null than we make our MySingletonClass object and give it to our private field
singletonInstance and than access through our public property
SingletonInstance.
2nd Version - simple thread-safety
private static SingletonClass instance = null;
private static readonly object padlock = new object();
SingletonClass()
{
}
public static SingletonClass Instance
{
get
{
lock (padlock)
{
if (instance == null)
{
instance = new SingletonClass();
}
return instance;
}
}
}
3rd Version - attempted thread-safety using double-check locking
// Bad
code! Do not use!
private static SingletonClass instance = null;
private static readonly object padlock = new object();
SingletonClass ()
{
}
public static SingletonClass Instance
{
get
{
if (instance == null)
{
lock (padlock)
{
if (instance == null)
{
instance = new SingletonClass();
}
}
}
return instance;
}
}
4th Version - not quite as lazy, but thread-safe without using locks
public sealed class Singleton
{
private static readonly Singleton instance = new Singleton();
// Explicit
static constructor to tell C# compiler
// not to mark
type as beforefieldinit
static Singleton()
{
}
private Singleton()
{
}
public static Singleton Instance
{
get
{
return instance;
}
}
}
5th Version - fully lazy instantiation
public sealed class Singleton
{
private Singleton()
{
}
public static Singleton Instance { get { return Nested.instance; } }
private class Nested
{
//
Explicit static constructor to tell C# compiler
// not to
mark type as beforefieldinit
static Nested()
{
}
internal static readonly Singleton instance = new Singleton();
}
}
6th Version - using .NET 4's Lazy<T> type
public sealed class Singleton
{
private static readonly Lazy<Singleton> lazy =
new Lazy<Singleton>(() => new Singleton());
public static Singleton Instance { get { return lazy.Value; } }
private Singleton()
{
}
}
Advantages:
The advantages of a Singleton Pattern are:
Singleton pattern can be implemented interfaces.
It can be also inherit from other classes.
It can be lazy loaded.
It has Static Initialization.
It can be extended into a factory pattern.
It helps to hide dependencies.
It provides a single point of access to a particular instance, so it is easy to maintain.
Disadvantages:
The disadvantages of a Singleton Pattern are:
Unit testing is more difficult (because it introduces a global state into an application).
This pattern reduces the potential for parallelism within a program, because to access the singleton in a multi-threaded system, an object must be serialized (by locking).
(Practice Makes a Man Perfect)
No comments:
Post a Comment