为 Task<T> 返回默认值或 null

Jos*_*osh 4 c# async-await

我有一个围绕 Cache 库的包装器,并有以下方法来检索基于 Key 的缓存值:

public async Task<T> GetAsync<T>(string key)
{
    var serializedObject = await _cache.GetStringAsync(key);

    return JsonConvert.DeserializeObject<T>(serializedObject);
}
Run Code Online (Sandbox Code Playgroud)

问题是缓存中没有任何内容,我从 DeserializeObject 方法收到错误。我被困在什么没有存储缓存时如何返回 null 或 T 的默认值。

我试过:

public async Task<T> GetAsync<T>(string key)
{
    var serializedObject = await _cache.GetStringAsync(key);

    if (serializedObject == null) return Task.CompletedTask;

    return JsonConvert.DeserializeObject<T>(serializedObject);
}
Run Code Online (Sandbox Code Playgroud)

但是 Task.CompletedTask 不能转换为 Task<T>

我试过:

public async Task<T> GetAsync<T>(string key)
    {
        var serializedObject = await _cache.GetStringAsync(key);

        if (serializedObject == null) return Task.FromResult<T>(null);

        return JsonConvert.DeserializeObject<T>(serializedObject);
    }
Run Code Online (Sandbox Code Playgroud)

但是 null 不是 T 的有效参数。

如何让 GetAsync 返回 null 或 T 的默认值?

更新

我得到了以下工作:

public async Task<T> GetAsync<T>(string key)
{
    var serializedObject = await _cache.GetStringAsync(key);

    return serializedObject == null ? default(T) : JsonConvert.DeserializeObject<T>(serializedObject);
}
Run Code Online (Sandbox Code Playgroud)

das*_*ght 9

您有三个选择:

  • 如果不需要支持值类型,添加T : class约束
  • 添加一个包装类,让您的调用者知道访问缓存是否成功,或者
  • 添加一个方法来构造和缓存不成功检索的新值。

第一个实现让你的方法编译:

public async Task<T> GetAsync<T>(string key) where T : class {
    var serializedObject = await _cache.GetStringAsync(key);
    if (serializedObject == null) {
        return await Task.FromResult<T>(null);
    }
    return JsonConvert.DeserializeObject<T>(serializedObject);
}
Run Code Online (Sandbox Code Playgroud)

这是第二个实现:

class CacheResult<T> {
    public bool IsSuccess {get;}
    public T Value {get;}
    public CacheResult(T val, bool isSuccess) {
        Value = val;
        IsSuccess = isSuccess;
    }
}
public async Task<CacheResult<T>> GetAsync<T>(string key) {
    var serializedObject = await _cache.GetStringAsync(key);
    if (serializedObject == null) {
        return new CacheResult(default(T), false);
    }
    return new CacheResult(
        JsonConvert.DeserializeObject<T>(serializedObject)
    ,   true
    );
}
Run Code Online (Sandbox Code Playgroud)

这是第三个实现:

public async Task<T> GetAsync<T>(string key, Func<string,T> make) {
    var serializedObject = await _cache.GetStringAsync(key);
    if (serializedObject == null) {
        var res = make(key);
        _cache.PutStringAsync(key, JsonConvert.SerializeObject(res));
        return res;
    }
    return JsonConvert.DeserializeObject<T>(serializedObject);
}
Run Code Online (Sandbox Code Playgroud)

如果缓存的对象不可用,调用者需要为第二个方法提供一个“工厂”委托,以便创建一个新对象。

  • @Josh 是的,当一个键碰巧映射到一个 `default(T)` 值时,它让调用者决定是否有缓存的值:例如,如果 `T` 是一个 `int`,这种方法让您决定是否将 `key` 映射到零,还是没有该键的值。具有所有默认值的 `struct` 也是如此。 (2认同)

Err*_*rra 5

你试过这个吗? return default(T);

因为您要返回 的默认值T,所以您不妨同步返回它。

  • `return default(T);` 或 `return wait Task.FromResult&lt;T&gt;(default(T));` 应该都可以,第一个选项更好 (2认同)