将通用委托 Action<T> 转换为 Action<string>

Casting generic delegate Action<T> to Action<string>

我正在努力实施 pub/sub 缓存使用模式。以下class假设用于发布任何类型的数据。订阅者可以在事件上附加 Action T 的回调。但是如果不使 class 通用,我就无法在 class 级别创建通用事件,我不想这样做。因此,我尝试使用 JsonSerializer 将值来回转换为字符串,如下所示。

public class CacheNotification
{
    public Action<string> CachePublished;

    public Task Publish<T>(T value)
    {
        var json = JsonSerializer.Serialize(value);
        OnCachePublished(json);
        return Task.CompletedTask;
    }

    public Task Subscribe<T>(Action<T> callback)
    {
        Action<string> newCallback = (string json) => 
                             callback(JsonSerializer.Deserialize<T>(json));
        CachePublished += newCallback;
        return Task.CompletedTask;
    }
    
    protected virtual void OnCachePublished(string value)
    {
        if(CachePublished != null){
              CachePublished.Invoke(value);
        }
    }
}

所以问题出在订阅方法上,我尝试的转换仅适用于 Action 字符串。它在 Action intAction object

上失败
public Task Subscribe<T>(Action<T> callback)
{
   Action<string> newCallback = (string json) => 
                     callback(JsonSerializer.Deserialize<T>(json));
   CachePublished += newCallback;
   return Task.CompletedTask;
}

这是我用过的一个测试。第二个订阅者失败

Action<string> sub1Callback = msg =>
{
    sub1Counter++;
};

Action<int> sub2Callback = num =>
{
    sub2Counter++;
};

var sub1 = await cache.Subscribe(sub1Callback);
var sub2 = await cache.Subscribe(sub2Callback);

await cache.Publish("Value1");
Assert.Equal(1, sub1Counter);
Assert.Equal(1, sub2Counter);

你的问题在这里:

Action sub2Callback = num =>

之后

await cache.Publish("Value1");

你的:

        public Task Subscribe<T>(Action<T> callback)
        {
               

Action newCallback = (string json) => callback(JsonSerializer.Deserialize(json));

               CachePublished += newCallback;
            return Task.CompletedTask;
        }

尝试将“Value1”反序列化为整数,但正确地失败了。做不到。

尝试发送整数值而不是“Value1”,它应该可以工作。

另一种方法是重构您的 Subscribe 方法,使其独立于给定类型,但我猜这不能按照您的意图来完成。