【问题标题】:Casting generic delegate Action<T> to Action<string>将通用委托 Action<T> 转换为 Action<string>
【发布时间】:2021-08-30 10:51:20
【问题描述】:

我正在努力实现 pub/sub 模式以供缓存使用。假设以下类用于发布任何类型的数据。订阅者可以在事件上附加ActionT 的回调。但是如果不使类成为通用类,我就无法在类级别创建通用事件,我不想这样做。因此,我尝试使用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);

【问题讨论】:

  • 您好,您的代码失败时会出现什么异常?
  • 仅基于您上次的 sn-p,仅发布字符串时您期望发生什么?您的解释对于您期望发生的事情非常混乱。是否应该只触发与传递值相同类型的动作?那么合并这两个完全不同的订阅的目的是什么?您也没有发布 sub1Countersub2Counter 的初始值,因此断言语句不会向读者传达任何信息。
  • “但是我不能在类级别创建一个通用事件而不使类通用,我不想这样做。” 你为什么不想做解决手头问题的事情吗?
  • 另外,虽然整数和(一些!)字符串之间可以进行转换,但在处理无法转换为另一种类型的类型时,您希望发生什么?
  • 谢谢你们的cmets。我现在看到了问题。

标签: c# .net-core publish-subscribe


【解决方案1】:

你的问题在这里:

动作 sub2Callback = num =>

之后

等待缓存.Publish("Value1");

你的:

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

动作 newCallback = (string json) => 回调(JsonSerializer.Deserialize(json));

               CachePublished += newCallback;
            return Task.CompletedTask;
        }

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

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

另一种方法是将您的订阅方法重构为独立于给定类型,但我猜这不能按照您的意图完成。

【讨论】:

    猜你喜欢
    • 2012-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-17
    • 1970-01-01
    • 2017-07-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多