.net 如何从静态类内部调用异步方法?

sd2nnvve  于 2022-11-19  发布在  .NET
关注(0)|答案(1)|浏览(166)

所以我在我的应用程序中使用Redis缓存(Stack Exchange Redis),我有一个静态类来创建连接。我希望能够在这个静态类的某个地方调用异步方法,但是我收到了一个错误“await运算符只能在异步lambda表达式中使用。考虑用异步修饰符创建这个lambda表达式。
我的静态类在下面。

public static class RedisConnection {
   private static ConnectionMultiplexer connMulti = null;
   private static Lazy<ConnectionMultiplexer> lazyConn = new Lazy<ConnectionMultiplexer>(() => {
         string redisConnString = "";  // Need to replace this with call to async method
         connectionMultiplexer = ConnectionMultiplexer.Connect(redisConnString);
         return connectionMultiplexer;
       });

       public static ConnectionMultiplexer Conn => lazyConn.Value;
}

基本上,我的注解是,我想用一个异步方法调用来替换那个变量,这个方法获取conn字符串。但是因为Stack Exchange Redis是如何设置的,ConnectionMultiplexer需要同步,所以我需要保持类静态,Lazy连接静态,lambda函数同步。请看下面

public static class RedisConnection {
   private static ConnectionMultiplexer connMulti = null;
   private static Lazy<ConnectionMultiplexer> lazyConn = new Lazy<ConnectionMultiplexer>(() => {
         var redisConnString = await getKey();  // Error
         connectionMultiplexer = ConnectionMultiplexer.Connect(redisConnString);
         return connectionMultiplexer;
       });

       public static ConnectionMultiplexer Conn => lazyConn.Value;
}

我能怎么办呢?

oyxsuwqo

oyxsuwqo1#

您可以做的是公开ValueTask<ConnectionMultiplexer>而不是ConnectionMultiplexer,如下所示

public static class RedisConnection
{
    private static Lazy<ValueTask<ConnectionMultiplexer>> lazyConn =
        new Lazy<ValueTask<ConnectionMultiplexer>>(
            async () => 
            {
                Console.WriteLine("Establishing connection asynchronously");
                var redisConnString = await GetKeyAsync();  
                var connectionMultiplexer = ConnectionMultiplexer.Connect(redisConnString);
                return connectionMultiplexer;
            });

    public static ValueTask<ConnectionMultiplexer> Conn => lazyConn.Value;

    private static Task<string> GetKeyAsync()
    {
        return Task.FromResult("asdf");
    }
}

则用法如下:

public class ExampleService
{
    public async Task GetSomeDataFromRedisAsync()
    {
        var connection = await RedisConnection.Conn;
     
        connection = await RedisConnection.Conn;
    }
}

因此using代码将负责等待连接。并且可能我们将多次调用此getter,这就是为什么我们使用ValueTask,因为在访问它时,大部分时间它都已完成。
我添加了Console.WriteLine和double establishing connection,以证明如果调用它两次,它将尝试连接一次--获取连接的其他调用将返回已完成的ValueTask,其中连接已准备就绪。
这里还有一件事是控制线程ssafety,但是你可以在google上很容易地找到关于异步代码中的线程安全和使用Lazy中的线程安全的资源-它甚至已经内置了实现:)(例如,一个构造函数重载接受threadSafe标志)

相关问题