过去提出的类似问题如下:
都找到了将Action<T> myActionT包装成匿名new Action<object>(o => myActionT((T)o));的解决方案。
我的用例是,初始的、类型化的lambda是一个数据订阅回调,将其封装到一个匿名的回调中,意味着我失去了使用原始Action<T>取消订阅的能力。
我把它缩小到了一个样板例子:
internal class Demo
{
public class Dispatcher
{
private List<Action<object>> callbacks = new List<Action<object>>();
public void Subscribe<T>(Action<T> cbk)
{
callbacks.Add(cbk); // <- compile error, Action<T> is contravariant
}
public void Unsubscribe<T>(Action<T> cbck)
{
callbacks.Remove(cbck); // <- compile error
}
}
private static void Handler(int v) {}
private static void Handler(string v) {}
public static void Main()
{
var dispatcher = new Dispatcher();
dispatcher.Subscribe<int>(Handler);
dispatcher.Subscribe<string>(Handler);
dispatcher.Unsubscribe<int>(Handler);
}
}当然,我可以选择重载Subscribe (因为实际上我只需要值类型)
是否有更好/更优雅的方法来正确跟踪通用Action回调?
稍后编辑:添加关于我的用例的更多细节:
updates
TypeDescriptor.GetConverter(type).ConvertFromString(fieldValue)处理转换)例如:
Subscribe<decimal>("price", (decimal px) => { /* do smthg with price*/ })
Subscribe<bool>("opened", (bool opened) => { ... })
Subscribe<string>("code", (string code) => { ... })我觉得我现在的方法(函数指针/代理,跟踪订阅类型)很难做到,但我没有找到更简单的方法来实现这一点(除了用我需要的类型重载Subscribe之外,这可能是一个明智的吻选择)
发布于 2020-07-22 09:52:28
太简单了。试一试:
private List<Delegate> callbacks = new List<Delegate>();C#编译器允许您将任何Action<T>转换为Delegate。您的代码编译并运行良好。
但是,我建议将您的Subscribe方法签名更改为:
IDisposable Subscribe<T>(Action<T> cbk)然后您就不需要Unsubscribe方法了--这将要求您保持对Action<T> cbk的引用。相反,您只需在订阅时调用.Dispose()。
尝试下面的代码:
internal class Demo
{
public class Dispatcher
{
private List<Delegate> callbacks = new List<Delegate>();
public IDisposable Subscribe<T>(Action<T> cbk)
{
callbacks.Add(cbk);
return new AnonymousDisposable(() => callbacks.Remove(cbk));
}
}
private static void Handler(int v) { }
private static void Handler(string v) { }
public static void Main()
{
var dispatcher = new Dispatcher();
var subscription = dispatcher.Subscribe<int>(Handler);
dispatcher.Subscribe<string>(Handler);
subscription.Dispose();
}
}
public sealed class AnonymousDisposable : IDisposable
{
private readonly Action _action;
private int _disposed;
public AnonymousDisposable(Action action)
{
_action = action;
}
public void Dispose()
{
if (Interlocked.Exchange(ref _disposed, 1) == 0)
{
_action();
}
}
}https://stackoverflow.com/questions/63031399
复制相似问题