【问题标题】:Action delegate reference in another class?另一个类中的动作委托引用?
【发布时间】:2019-03-13 11:10:13
【问题描述】:

我正在寻找一种方法,允许另一个类通过调用该类的方法向我的 Action 委托添加方法,而不是在第一个类上调用 Action。

这是我需要的:

class Program
{
    static void Main(string[] args)
    {
        Action Execute = delegate { };

        ProgramTest prog = new ProgramTest(ref Execute);

        prog.AddMethod();

        Execute();
    }
}

class ProgramTest
{
    public Action execute;

    public ProgramTest(ref Action action)
    {
        execute = action;
    }

    public void AddMethod()
    {
        execute += Print;
    }

    public void Print()
    {
        Console.WriteLine("test");
        Console.ReadLine();
    }
}

但是,当我调用 Execute() 时,什么都没有发生。

我怎样才能让它工作?

【问题讨论】:

  • 你不能——不像这样。委托是不可变类型 - += 创建一个新委托。您传递 ref Action action 的事实什么也没做,因为 execute 字段不是 ref(也不能是)

标签: c# delegates action


【解决方案1】:

另一种选择是将(不可变的)委托放入可变容器中。

public class ActionContainer
{
    public Action Action { get; set; } = () => { };
}

class Program
{
    static void Main(string[] args)
    {
        ActionContainer execute = new ActionContainer();

        ProgramTest prog = new ProgramTest(execute);

        prog.AddMethod();

        execute.Action();
    }
}

class ProgramTest
{
    public ActionContainer execute;

    public ProgramTest(ActionContainer action)
    {
        execute = action;
    }

    public void AddMethod()
    {
        execute.Action += Print;
    }

    public void Print()
    {
        Console.WriteLine("test");
        Console.ReadLine();
    }
}

【讨论】:

  • 太棒了,非常简单,可以完成这项工作。允许我在任何地方使用 Action 委托。谢谢!
【解决方案2】:

你想要的是这个:

class Program
{
    static void Main(string[] args)
    {
        Action Execute = delegate { };

        ProgramTest prog = new ProgramTest(h => Execute += h);

        prog.AddMethod();

        Execute();
    }
}

class ProgramTest
{
    public Action<Action> execute;

    public ProgramTest(Action<Action> action)
    {
        execute = action;
    }

    public void AddMethod()
    {
        execute(Print);
    }

    public void Print()
    {
        Console.WriteLine("test");
        Console.ReadLine();
    }
}

这会将test 打印到控制台。


这是这个模式的一个稍微好一点的版本:

class Program
{
    static void Main(string[] args)
    {
        Action Execute = delegate { };

        ProgramTest prog = new ProgramTest(h => Execute += h, h => Execute -= h);

        var subscription = prog.AddMethod();

        Execute();

        subscription.Dispose();
    }
}

class ProgramTest
{
    public Action<Action> _attach;
    public Action<Action> _detach;

    public ProgramTest(Action<Action> attach, Action<Action> detach)
    {
        _attach = attach;
        _detach = detach;
    }

    public IDisposable AddMethod()
    {
        _attach(Print);
        return Disposable.Create(() => _detach(Print));
    }

    public void Print()
    {
        Console.WriteLine("test");
        Console.ReadLine();
    }
}

public sealed class Disposable : IDisposable
{
    public static IDisposable Create(Action action)
        => new Disposable(action);

    private readonly Action _action;
    private int _disposed;

    private Disposable(Action action)
    {
        _action = action;
    }

    public void Dispose()
    {
        if (Interlocked.Exchange(ref _disposed, 1) == 0)
        {
            _action();
        }
    }
}

我什至会更进一步,定义一个 MetaAction - 您可以随意传递它并向其添加方法。

class Program
{
    static void Main(string[] args)
    {
        Action Execute = delegate { };

        MetaAction meta = MetaAction.Create(h => Execute += h, h => Execute -= h);

        var prog = new ProgramTest(meta);

        var subscription = prog.AddMethod();

        Execute();

        subscription.Dispose();
    }
}

public class MetaAction
{
    public static MetaAction Create(Action<Action> attach, Action<Action> detach)
        => new MetaAction(attach, detach);

    public Action<Action> _attach;
    public Action<Action> _detach;

    private MetaAction(Action<Action> attach, Action<Action> detach)
    {
        _attach = attach;
        _detach = detach;
    }

    public IDisposable Subscribe(Action action)
    {
        _attach(action);
        return Disposable.Create(() => _detach(action));
    }
}

public class ProgramTest
{
    public MetaAction _meta;

    public ProgramTest(MetaAction meta)
    {
        _meta = meta;
    }

    public IDisposable AddMethod()
    {
        return _meta.Subscribe(Print);
    }

    public void Print()
    {
        Console.WriteLine("test");
        Console.ReadLine();
    }
}

public sealed class Disposable : IDisposable
{
    public static IDisposable Create(Action action)
        => new Disposable(action);

    private readonly Action _action;
    private int _disposed;

    private Disposable(Action action)
    {
        _action = action;
    }

    public void Dispose()
    {
        if (Interlocked.Exchange(ref _disposed, 1) == 0)
        {
            _action();
        }
    }
}

【讨论】:

  • 成功了!谢谢!但是如何删除和添加新的方法调用到 Action 委托?
  • @JohnnyB - 你不能。执行h =&gt; Execute += h, h =&gt; Execute -= h 是唯一可行的方法。
【解决方案3】:

您可以通过调用 prog.Execute 而不是 Execute 来使其工作,就像下面的代码一样。

class Program
{
    static void Main(string[] args)
    {
        Action Execute = delegate { };
        ProgramTest prog = new ProgramTest(ref Execute);
        prog.AddMethod();
        prog.execute();
    }
}

或 您需要将 Print 方法分配给 main 方法执行委托,如下所示

class Program
{
    static void Main(string[] args)
    {
        Action Execute = delegate { };            
        ProgramTest prog = new ProgramTest(ref Execute);

        Execute += prog.Print;

        prog.AddMethod();

        Execute();

    }
}

【讨论】:

  • 感谢您的回复。但是我有几个不同的类可以向该委托添加方法。主类本身不知道什么时候会发生以及哪些对象会这样做。
【解决方案4】:

您的Program 可能会公开一个事件,您的其他类可能会向该事件注册另一个处理程序:

class Program
{
    public static event Action MyEvent;
    static void Main(string[] args)
    {
        ProgramTest prog = new ProgramTest();

        prog.AddMethod();

        // raise the event and invoke the registered handlers
        MyEvent?.Invoke();
    }
}

class ProgramTest
{
    private Action handler;

    public ProgramTest()
    {
        handler = Print;
    }

    public void AddMethod()
    {
        Program.MyEvent += handler;  // regsiter the execute-delegate to the event
        // or directly: Program.MyEvent += Print;
    }

    public void Print()
    {
        Console.WriteLine("test");
        Console.ReadLine();
    }
}

【讨论】:

  • 我觉得你在发帖之前可能没有测试过这个。
猜你喜欢
  • 2015-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多