Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to populate dictionary of Func<T> dynamically

Consider the following:

public interface ISomething
{
    string Something();
}

public class A : ISomething
{
    public string Something()
    {
        return "A";
    }
}

public class B : ISomething
{
    public string Something()
    {
        return "B";
    }
}

public class Helper
{
    private static readonly Dictionary<string, Func<string, string>> Actions =
                new Dictionary<string, Func<string, string>>(StringComparer.OrdinalIgnoreCase);

    public Helper()
    {
        Actions["A"] = DoSomething<A>;
        Actions["B"] = DoSomething<B>;


        var types = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.GetInterfaces().Contains(typeof(ISomething)));
        foreach (var type in types)
        {
            Console.WriteLine(type.Name);
            // Actions[type.Name] = ????;
        }
    }

    public static string DoSomething<T>(string data) where T : ISomething
    {
        T obj = JsonConvert.DeserializeObject<T>(data);

        // Some manipulations

        return obj.Something();

    }
}

void Main()
{
   var h = new Helper();
}

I am able fill dictionary manually. However is it possible add it dynamically?

How I may convert generic method to Func?

like image 431
Michael Pakhantsov Avatar asked Mar 19 '15 08:03

Michael Pakhantsov


1 Answers

You could create an Expression and compile it to a Func<string, string>:

public Helper()
{
    var types = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.GetInterfaces().Contains(typeof(ISomething)));
    foreach (var type in types)
    {
        var data = Expression.Parameter(typeof(string), "data");
        var call = Expression.Call(typeof(Helper), "DoSomething", new Type[] { type }, data);
        var lambda = Expression.Lambda(call, data);

        Actions[type.Name] = (Func<string, string>)lambda.Compile();
    }
}
like image 174
sloth Avatar answered Sep 23 '22 23:09

sloth