如何将一个已知类型的值转换为泛型类型 T?

4

我正在尝试在.NET Core应用程序中使用Azure Redis Cache。我编写了一个CacheHelper通用方法,该方法实现了以下通用接口。

但是这个问题与泛型更相关。

当我将缓存值转换为通用类型时,我遇到了错误。这是正确的方式吗?还是我漏掉了什么?请参见下面的代码。

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();
        }
    }
}

1
你期望什么?value是一个RedisValue,构造函数需要类型T - 你必须进行强制转换或其他转换。 - fredrik
什么是 CacheResponse?你能提供它的文档链接吗? - Patrick Hofman
@fredrik,是的,我知道我需要进行转换。我尝试过一些选项进行转换,如Convert.ChangeType(value, typeof(T)),将其显式地强制转换为T,例如(T)value,但都没有成功。 - PNDev
@PatrickHofman 这是一个自定义编写的类。我想要格式化响应。 - PNDev
在 Redis 中存储的数据如何进行反转? - fredrik
为什么 Convert.ChangeType 对你无效? - Martin Zikmund
3个回答

3
您可以利用内置的Convert类来实现此功能:
new CacheResponse<T>((T)Convert.ChangeType(value, typeof(T));

1
你如何知道 T 实现了 IConvertible 接口?根据文档,这是必须的才能使转换工作。 - Patrick Hofman
1
在这种情况下,它确实会生效 - 一旦我们进入if语句的这个分支,我们已经知道Tstring,因此这将按预期工作。 - Martin Zikmund
“value” 似乎是一个 “RedisValue”,但 “T” 可以是 “string”,但这并不意味着 “value” 是可转换的。 - Patrick Hofman
哦,你说得对,我漏掉了。但是它仍然实现了它 - https://github.com/StackExchange/StackExchange.Redis/blob/d9a5ee7fc4f1d4daef10bce4fc33e1188d6a8db2/src/StackExchange.Redis/RedisValue.cs#L13 - Martin Zikmund
RedisValue 转换为字符串是有效的,我认为这应该可以工作。让我试一试。 - PNDev
RedisValue 实现了 IConvertible 接口。感谢 @Martin Zikmund 指出这一点。当我最初尝试使用 Convert.ChangeType 时,我只是尝试了 Convert.ChangeType(value, typeof(T)) 而不是 (T)Convert.ChangeType(value, typeof(T)),这是我的错误。后者对我起作用了。 - PNDev

0

我想分享一种将RedisValue转换为'T'类型的实现方式。RedisValue实现了IConvertible接口,该接口具有将实例值转换为公共语言运行时类型的方法。这可能对某些人有所帮助。

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);
}

-1

在我看来,如果 ICacheHelper<T> 接口,你应该创建两个不同的实现。 一个是针对 string 类型的,它实现了 ICacheHelper<string>。 另一个是针对所有其他类型的,它实现了 ICacheHelper<T>


2
这与这个问题有什么关系? - Patrick Hofman
只发生在他身上,是因为他尝试将stringT进行完全相同的处理。如果您编写仅处理“string”的代码,则不会犯这个错误。 - selalerer
你说得对。整个ICacheHelper都有一个泛型参数,而你期望Get()方法只有一个。 - CodeCaster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接