Simple Custom Attributes in C#

share1.pngThink of an Attribute as paint you can apply to a class that doesn’t necessarily need to know about the attribute, though it can.

Imagine we have a Alien Immigration system where space aliens are arriving. The class is decorated by a LifeDanger Attribute.

[LifeDanger(IsHuman = false)]
public class AlienImmigration
{}

The Attribute looks like this. It decides if an space alien is dangerous (Only humans are dangerous of course):

public class LifeDangerAttribute : Attribute
{
    public bool IsHuman { getset; }
    public bool IsDanger => IsHuman;
}

We can now create an Alien and see if they are dangerous:

public Test()
{
    //Create an Alien
    var bobTheAlien = new AlienImmigration();
 
    //Get the LifeDanger attribute
    System.Attribute[] attrs = 
            System.Attribute.GetCustomAttributes(bobTheAlien.GetType());
    var life = (LifeDangerAttribute) attrs
           .FirstOrDefault(x => x is LifeDangerAttribute);
 
    //Display the Danger
    Console.WriteLine("Dangerous?: " + life?.IsDanger);
}

Summary:  You can imagine creating other Immigration Types and using the same code to see if that Immigrant is dangerous. This allows users of your classes to apply meta data about the classes without having to change the class.

Advertisements

C#: Using Task.FromResult() to wrap a value when there is no Task

c.pngTask.FromResult() creates a finished Task that holds a value in its Result property. It allows you to create a pre-computed task.

What good is that? Imagine you have been told that you need to create a class that implements this simple Interface:

public interface IEquity
{
    Task<string> GetEquityTask(string id);
}

Most of the time your implementation will get the Equity from a fast cache but the return value of the Interface is a Task and your cache doesn’t return Tasks, it returns an Equity.  You can wrap the Equity in a Task with Task.FromResult:

public class Equity : IEquity
{
    public Task<string> GetEquityTask(string id)
    {
        //Get the Equity from cache
        var equityFromCache = GetEquityFromCache(id);
 
        //If the Equity is found return it wrapped in a Task 
        //to fulfull the interface
        if (!string.IsNullOrWhiteSpace(equityFromCache))
        {
            //Wrap the Equity in a Task
            return Task.FromResult<string>(equityFromCache);
        }
 
        //No cache hit? Ok, then go get a Task which will get the Equity
        //from a slow backend.
        return Task.Run<string>(async () =>
        {
            var equity= await GetEquityFromDatabaseAsync(id);
            AddEquityToCache(id,equity);
            return equity;
        });
      
    }

……

}

To use this now, we can simple wrap a bunch of Tasks into a Task.WhenAll()

class Program
{
    static void Main(string[] args)
    {
        var ids = new[] {"A1""A2""A3"};
        var tasks = from id in ids
            select new Equity().GetEquityTask(id);
        Task.WhenAll(tasks).ContinueWith(equities=>
        {
            foreach (var equity in equities.Result)
            {
                Console.WriteLine(equity);
            }
        }).Wait();
    }
}