PNDev
PNDev

Reputation: 750

How to cast a typed value to generic type T?

I'm trying to use Azure Redis Cache in .NET Core application. I have written a CacheHelper generic method which implements generic interface like below.

However this issue is more related to Generics.

I'm getting error while casting cache value to generic type. Is this the correct way to do? or Am i missing something? Please see the code below.

public class CacheHelper<T> : ICacheHelper<T>
{
    private ICacheProvider _cacheProvider;

    public CacheHelper(ICacheProvider cacheProvider)
    {
        _cacheProvider = cacheProvider;
    }

    public async Task<CacheResponse<T>> GetCacheValueAsync(string key)
    {
        RedisValue value = await _cacheProvider.GetCacheDatabase().StringGetAsync(key);
        if (typeof(T).Equals(typeof(string)))
        {
            return value.HasValue
            ? new CacheResponse<T>(value) //I'm getting error here cannot cast type RedisValue to type T
            : CacheResponse<T>.NoValue();
        }
        else
        {
            T obj = JsonConvert.DeserializeObject<T>(value);
            return value.HasValue
           ? new CacheResponse<T>(obj)
           : CacheResponse<T>.NoValue();
        }
    }
}

Upvotes: 4

Views: 1811

Answers (3)

Mrugesh
Mrugesh

Reputation: 61

I would like to share one more implementation of converting RedisValue to 'T' type. RedisValue implements IConvertible interface and this interface has methods to convert the instance value to a common language runtime type. This might be helpful to someone.

private RedisValue GetStringInRedis(string key)
{
    var redisDb = RedisConnection.GetDatabase();

    var redisValue = redisDb.StringGet(redisKey);
    if (redisValue.HasValue)
    {
        return redisValue;
    }

    return RedisValue.Null;
 }

private T ChangeToType<T>(string key, RedisValue redisValue)
{
    if (redisValue.IsNull)
        return default(T);

    try
    {
        var sRedisValue = redisValue;
        if (typeof(T) == typeof(bool))
        {
            var tempRedisValue = (string) redisValue;
            if (tempRedisValue.ToLower() == "true")
                sRedisValue = RedisValue.Unbox(1);
            else
                sRedisValue = RedisValue.Unbox(0);
        }

        var obj = Convert.ChangeType(sRedisValue, typeof(T));
        return (T) obj;
    }
    catch
    {
        throw new Exception($"Redis key '{key}' has invalid redis value '{redisValue}'");
    }
}

public T GetValue<T>(string key)
{
    var redisValue = GetStringInRedis(key);
    return ChangeToType<T>(key, redisValue);
}

Upvotes: 0

Martin Zikmund
Martin Zikmund

Reputation: 39072

You could use the built-in Convert class to your advantage here:

new CacheResponse<T>((T)Convert.ChangeType(value, typeof(T));

Upvotes: 3

selalerer
selalerer

Reputation: 3924

It seems to me you should create two different implementations if ICacheHelper<T> interface. One for the string type that implements ICacheHelper<string>. One for all other types that implements ICacheHelper<T>.

Upvotes: -1

Related Questions