C# 跟踪行动<;T>;lambdas as Action<;对象>;

C# 跟踪行动<;T>;lambdas as Action<;对象>;,c#,generics,delegates,C#,Generics,Delegates,过去提出的类似问题: 所有人都找到了将动作myActionT包装成匿名新动作(o=>myActionT((T)o))的解决方案 我的用例是,初始的、类型化的lambda是一个数据订阅回调,将其包装成匿名回调意味着我无法使用原始的操作取消订阅 我把范围缩小到这个样板示例: internal class Demo { public class Dispatcher { private List<Action<

过去提出的类似问题:

所有人都找到了将
动作myActionT
包装成匿名
新动作(o=>myActionT((T)o))的解决方案
我的用例是,初始的、类型化的lambda是一个数据订阅回调,将其包装成匿名回调意味着我无法使用原始的
操作取消订阅

我把范围缩小到这个样板示例:

    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
,这可能是明智的选择)

它非常简单。请尝试以下方法:

private List<Delegate> callbacks = new List<Delegate>();
然后,您不需要
取消订阅
方法-这将要求您保留对
操作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();
        }
    }
}
内部类演示
{
公共类调度器
{
私有列表回调=新列表();
公共IDisposable订阅(操作cbk)
{
callbacks.Add(cbk);
返回新的匿名(()=>callbacks.Remove(cbk));
}
}
私有静态无效处理程序(int v){}
私有静态无效处理程序(字符串v){}
公共静态void Main()
{
var dispatcher=newdispatcher();
var subscription=dispatcher.subscripte(处理程序);
dispatcher.Subscribe(处理程序);
subscription.Dispose();
}
}
公开密封类:IDisposable
{
私有只读操作\u操作;
私人INTU;
公众匿名(行动)
{
_行动=行动;
}
公共空间处置()
{
if(联锁交换(参考_,1)==0)
{
_动作();
}
}
}

“因为我实际上只需要值类型”<代码>字符串
不是值类型。除订阅/取消订阅外,您还计划如何处理
回调
。你也研究过了吗?我添加了一些关于我如何使用
回调的详细信息
@AlinMotogna-你考虑过使用微软的Rx吗?直到现在才听说过,对于我的简单用例来说,它看起来很重,但我一定会研究它。谢谢
IDisposable Subscribe<T>(Action<T> cbk)
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();
        }
    }
}