Reflections and Attributes

The .NET reflection services allow you to discover, using APIs from the System.Reflection namespace, the same information that you can see with the tools mentioned earlier. The key to this process is the type called System.Type, which contains members that expose all of a type’s metadata. This is done with the help of other types from the System.Reflection namespace

class A
{
    public int val;
    public int value
    {
        private set
        {
            val = value;
        }
        get
        {
            return val;
        }
    }
    public A(int i)
    {
        this.val = i;   
    }
}

A a=new A(12);
Type t1 =typeof(A);
Type t2 = a.GetType();
Type t3=Type.GetType("A");
Console.WriteLine((t1 == t2) && (t1 == t3));//true
A aa=(A)Activator.CreateInstance(t1, 12);
t1.GetProperty("value").GetSetMethod(true)?.Invoke(aa, new object[] { 44 });
Console.WriteLine(t1.GetField("val").GetValue(aa));//44

Attributes

Attributes provide meta-information about assemblies, types, and members. This meta-information is consumed by the compiler, the CLR, or tools that use reflection services to read them. Attributes are actually types that derive from the System.Attribute abstract class.

class DescriptionAttribute : Attribute
{
    public string Text { get; private set; }
    public bool Required { get; set; }
    public DescriptionAttribute(string description)
    {
        Text = description;
    }
}
[Description("Main component of the car", Required = true)]
class Engine
{
}
[AttributeUsage(AttributeTargets.Class|
                AttributeTargets.Struct|
                AttributeTargets.Method|
                AttributeTargets.Property|
                AttributeTargets.Field,
                AllowMultiple = true,
                Inherited = true)]
class DescriptionAttribute : Attribute
{
    public string Text { get; private set; }
    public bool Required { get; set; }
    public DescriptionAttribute(string description)
    {
        Text = description;
    }
}
[Serializable]
[Description("Main component of the car")]
[ComVisible(false)]
class Engine
{
}
[Serializable, 
 Description("Main component of the car"), 
 ComVisible(false)]
class Engine
{
}

Attributes In Reflections

var e = new Engine("M270 Turbo", 1600, 75.0);
var type = e.GetType();
var attributes = type.GetCustomAttributes(typeof(DescriptionAttribute), 
                                          true);
if (attributes != null)
{
    foreach (DescriptionAttribute attr in attributes)
    {
        Console.WriteLine(attr.Text);
    }
}
var properties = type.GetProperties();
foreach (var property in properties)
{
    var pattributes = 
      property.GetCustomAttributes(
         typeof(DescriptionAttribute), false);
    if (attributes != null)
    {
        foreach (DescriptionAttribute attr in pattributes)
        {
            Console.WriteLine(
              $"{property.Name} [{attr.Text}]");
        }
    }
}

Delgates , Events And Lambda expressions

Delegates

delegate is defined using the delegate keyword. The declaration looks like a function signature, but the compiler actually introduces a class that can hold references to methods whose signatures match the signature of the delegate. A delegate can hold references to either static or instance methods.

public enum Status { Started, Stopped }
public delegate void StatusChange(Status status);
public class Engine
{
    private StatusChange statusChangeHandler;// is Delegate return true
    public void RegisterStatusChangeHandler(StatusChange handler)
    {
        statusChangeHandler = handler;
    }
    public void Start()
    {
        // start the engine
        if (statusChangeHandler != null)
            statusChangeHandler(Status.Started);
    }
    public void Stop()
    {
        // stop the engine
        if (statusChangeHandler != null)
            statusChangeHandler(Status.Stopped);
    }
}

Combining delegates

ExpressionResult
null + d1d1
d1 + nulld1
d1 + d2[d1, d2]
d1 + [d2, d3][d1, d2, d3]
[d1, d2] + [d2, d3][d1, d2, d2, d3]
[d1, d2] – d1d2
[d1, d2] – d2d1
[d1, d2, d1] – d1[d1, d2]
[d1, d2, d3] – [d1, d2]d3
[d1, d2, d3] – [d2, d1][d1, d2, d3]
[d1, d2, d3, d1, d2] – [d1, d2][d1, d2, d3]
[d1, d2] – [d1, d2]null

Events

Events aren’t Delegate instances.

using System;

class Test
{
    public event EventHandler MyEvent
    {
        add
        {
            Console.WriteLine ("add operation");
        }
        
        remove
        {
            Console.WriteLine ("remove operation");
        }
    }  
    static void Main()
    {
        Test t = new Test();
        
        t.MyEvent += new EventHandler (t.DoNothing);
        t.MyEvent -= null;
    }
    void DoNothing (object sender, EventArgs e)
    {
    }
}
private EventHandler _myEvent;
    
public event EventHandler MyEvent
{
    add
    {
        lock (this)
        {
            _myEvent += value;
        }
    }
    remove
    {
        lock (this)
        {
            _myEvent -= value;
        }
    }        
}

Lambda expressions

  • The variables that are introduced in a lambda expression are not visible outside the lambda (for instance, in the enclosing method).
  • A lambda cannot capture inref, or out parameters from the enclosing method.
  • Variables that are captured by a lambda expression are not garbage collected, even if they would otherwise go out of scope until the delegate that the lambda is assigned to is garbage collected.
bool IsOdd(int n) { return n % 2 == 1; }
var list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
list.RemoveAll(IsOdd);
var list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
list.RemoveAll(delegate (int n) { return n % 2 == 1; });
var list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
list.RemoveAll(n => n % 2 == 1);