Search code examples
c#resharperfxcop

Code is heuristically unreachable when getting object from cache


I have the following code, the idea is simple if the object is in cache get it, if not then retrieve it from the data source and save it into cache, I am using resharper and I got this warning but cant understand why

 public static ModulosPorUsuario GetModulesForUser(string identityname)
        {
            // It needs to be cached for every user because every user can have different modules enabled.
            var cachekeyname = "ApplicationModulesPerUser|" + identityname;

            var cache = CacheConnectionHelper.Connection.GetDatabase();
            ModulosPorUsuario modulosUsuario;

            //get object from cache
            string modulosUsuariosString = cache.StringGet(cachekeyname);

            // ReSharper disable once ConditionIsAlwaysTrueOrFalse
            if (modulosUsuariosString != null)
            {
                //conver string to our object
                modulosUsuario = JsonConvert.DeserializeObject<ModulosPorUsuario>(modulosUsuariosString);
                return modulosUsuario;
            }
            // ReSharper disable once HeuristicUnreachableCode
            modulosUsuario = DbApp.ModulosPorUsuario.Where(p => p.Email == identityname).FirstOrDefault();

            //convert object to json string
            modulosUsuariosString = JsonConvert.SerializeObject(modulosUsuario);

            //save string in cache
            cache.StringSet(cachekeyname, modulosUsuariosString, TimeSpan.FromMinutes(SettingsHelper.CacheModuleNames));
            return modulosUsuario;
        }

Solution

  • There's quite a lot going on here, but the bottom line, this is a ReSharper bug - the value can certainly be null, and I have a much smaller example proving it.

    First, let's figure out what's going on in your code. I had to dig a little bit into the StackExchange.Redis library that you're using. Your cache object is, in fact, an IDatabase, which is implemented by the RedisDatabase class. The StringGet method that you're using returns a RedisValue, which is a struct. This, by itself, would make perfect sense why ReSharper tells you it can never be null - value types can't!

    However, you're putting the result into a string variable! This works because the RedisValue struct defines a bunch of implicit operators to convert the value into the requested type. In case of a string, notice that if the blob is empty, an empty string is returned:

    RedisValue.cs

    /// <summary>
    /// Converts the value to a String
    /// </summary>
    public static implicit operator string(RedisValue value)
    {
        var valueBlob = value.valueBlob;
        if (valueBlob == IntegerSentinel)
            return Format.ToString(value.valueInt64);
        if (valueBlob == null) return null;
    
        if (valueBlob.Length == 0) return "";
        try
        {
            return Encoding.UTF8.GetString(valueBlob);
        }
        catch
        {
            return BitConverter.ToString(valueBlob);
        }
    }
    

    But from this code it's obvious that the string can be null as well.

    This makes ReSharper incorrect to flag that line, and it can be reproduced with a smaller example:

    static void Main(string[] args)
    {
        string value = MyStruct.GetValue();
        if (value == null) // <- ReSharper complains here, but the value is null!
        {
            return;
        }
    }
    
    public struct MyStruct
    {
        public static MyStruct GetValue() => new MyStruct();
    
        public static implicit operator string(MyStruct s)
        {
            return null;
        }
    }
    

    I reported this issue to JetBrains, they will fix it.

    In the meantime, you might want to keep that comment, disabling ReSharper warning.