0

I have a lot of method and I need to put some of it in cache. but I don't want it edit each method.

how can I pass a dynamic method with return value as parameter? kindly check comments as some of my question in my code.

Thank you for advance.

private string GetUserName(string userId)
        {
            // how can I pass the method as parameter? 
            // Method is dynamic and can be any method with parameter(s) and return value
            return CacheIt<string>(item => GetUserNameFromDb(userId)); 
        }

        private T CacheIt<T>(Action<T> action) // Im not sure if this an Action
        {
            var key = "UserInfo." + userId; // how can I get the value of the parameter?

            var cache = MemoryCache.Default;
            var value = (T) cache[key];

            if (value != null)
                return value;

            value = action(); // how can I call the action or the method

            var policy = new CacheItemPolicy { SlidingExpiration = new TimeSpan(1, 0, 0) };
            cache.Add(key, value, policy);

            return value;

        }

        private string GetUserNameFromDb(string userId)
        {
            return "FirstName LastName";
        }
  • If you need to pass a method as a parameter you should use a [delegate](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates/using-delegates). There are predefined generic ones like `Action`, `Func` and `Predicate` [see here](https://stackoverflow.com/questions/566860/delegates-predicate-action-func) – royalTS Nov 28 '17 at 06:54

2 Answers2

1

Modify CacheIt method like this; Input parameter are passed as object type to method and for creating cache key the input object is serialized as Json and the json result is calculated to MD5. MD5 result is stored in cache as key. Also, Action doesn't return value and I used Func instead of Action. We are expecting to return value for caching.

    private T2 CacheIt<T2>(Func<T2> func, object input)
    {
        var key = CreateMD5(JsonConvert.SerializeObject(input));
        var cache = MemoryCache.Default;
        var value = cache.Get(key);
        if (value != null)
        {
            return (T2)value;
        }
        value = func();
        var policy = new CacheItemPolicy { SlidingExpiration = new TimeSpan(1, 0, 0) };
        cache.Add(key, value, policy);
        return (T2)value;
    }

    private string CreateMD5(string input)
    {
        using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
        {
            byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
            byte[] hashBytes = md5.ComputeHash(inputBytes);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < hashBytes.Length; i++)
            {
                sb.Append(hashBytes[i].ToString("X2"));
            }
            return sb.ToString();
        }
    }

Finally, GetUserName and GetUserNameFromDb methods look like this;

    private string GetUserName(string userId,string anotherParameter)
    {
        return CacheIt<string>(() => GetUserNameFromDb(userId, anotherParameter), new { userId,anotherParameter });
    }

    private string GetUserNameFromDb(string userId, string anotherParameter)
    {
        return "FirstName LastName";
    }

Usage;

GetUserName("1","AnotherParameter");

Note : Maybe there might be a better way to get input parameters from directly from func in CacheIt method.

lucky
  • 12,734
  • 4
  • 24
  • 46
0

We can pass method dynamically irrespective of method definition by

 public T CacheIt<T>(object container,string methodName,params object[] parameterlist)
    {
        MethodInfo func = container.GetType().GetMethod(methodName);
        var cache = MemoryCache.Default;
        T value = (T)cache.Get(func.Name);
        if(value!=null)
        {
            return value;
        }
        value = (T)func.Invoke(container,parameterlist);

        cache.Add(func.Name, value,new CacheItemPolicy());
        return value;

    }

    public void PrintUserName()
    {
     CacheIt<string>(this,nameof(this.GetUserName),"1");
        CacheIt<string>(this, nameof(this.GetFullName), "Raghu","Ram");
        Console.Read();
    }

    public string GetUserName(string userId)
    {
        // how can I pass the method as parameter? 
        // Method is dynamic and can be any method with parameter(s) and return value
        //return CacheIt<string>(item => GetUserNameFromDb(userId));
        return $"UserId : {userId} & UserName:Vaishali";
    }

    public string GetFullName(string FirstName,string  LastName)
    {
        return $"FullName : {string.Concat(FirstName," ",LastName)}";
    }

It will work fine with 'out' and 'ref' variables but it is not easy to get values of out and ref variable, for this we have to do more work on ParameterInfo stuff.