gpt4 book ai didi

c# - 将任何委托(delegate)作为参数的构造函数

转载 作者:太空狗 更新时间:2023-10-29 21:32:51 25 4
gpt4 key购买 nike

这是简化的情况。我有一个存储委托(delegate)的类,它将在完成时调用:

public class Animation
{
public delegate void AnimationEnd();
public event AnimationEnd OnEnd;
}

我有另一个实用程序类,我想订阅各种委托(delegate)。在构造时,我希望自己注册到委托(delegate)中,但除此之外它不关心类型。问题是,我不知道如何在类型系统中表达它。这是我的伪 C#

public class WaitForDelegate
{
public delegateFired = false;

// How to express the generic type here?
public WaitForDelegate<F that's a delegate>(F trigger)
{
trigger += () => { delegateFired = true; };
}
}

提前致谢!


感谢 Alberto Monteiro,我只使用 System.Action 作为事件的类型。我现在的问题是,如何将事件传递给构造函数以便它可以注册自己?这可能是一个非常愚蠢的问题。

public class Example
{
Animation animation; // assume initialized

public void example()
{
// Here I can't pass the delegate, and get an error like
// "The event can only appear on the left hand side of += or -="
WaitForDelegate waiter = new WaitForDelegate(animation.OnEnd);
}
}

最佳答案

恐怕你不能按照你的要求去做。

首先,您不能受委托(delegate)约束。最接近合法 C# 的代码是这样的:

public class WaitForDelegate<F> where F : System.Delegate
{
public bool delegateFired = false;

public WaitForDelegate(F trigger)
{
trigger += () => { delegateFired = true; };
}
}

但它不会编译。

但更大的问题是无论如何你都不能像这样传递委托(delegate)。

考虑这个简化的类:

public class WaitForDelegate
{
public WaitForDelegate(Action trigger)
{
trigger += () => { Console.WriteLine("trigger"); };
}
}

然后我尝试像这样使用它:

Action bar = () => Console.WriteLine("bar");

var wfd = new WaitForDelegate(bar);

bar();

唯一的输出是:

bar

单词trigger没有出现。这是因为委托(delegate)是按值复制的,因此行 trigger += () => { Console.WriteLine("trigger"); };仅将处理程序附加到 trigger而不是 bar完全没有。

您可以使所有这些工作的方法是停止使用事件并使用 Microsoft 的 Reactive Extensions(NuGet“Rx-Main”),它允许您将事件转换为基于 LINQ 的 IObservable<T>可以传递的实例。

下面是我上面的示例代码的工作方式:

public class WaitForDelegate
{
public WaitForDelegate(IObservable<Unit> trigger)
{
trigger.Subscribe(_ => { Console.WriteLine("trigger"); });
}
}

现在你这样调用它:

Action bar = () => Console.WriteLine("bar");

var wfd = new WaitForDelegate(Observable.FromEvent(h => bar += h, h => bar -= h));

bar();

这现在产生输出:

bar
trigger

请注意 Observable.FromEvent调用包含在有权访问的范围内附加和分离处理程序的代码。它允许最终订阅调用与对 .Dispose() 的调用无关.

我已经让这个类变得非常简单,但更完整的版本是这样的:

public class WaitForDelegate : IDisposable
{
private IDisposable _subscription;

public WaitForDelegate(IObservable<Unit> trigger)
{
_subscription = trigger.Subscribe(_ => { Console.WriteLine("trigger"); });
}

public void Dispose()
{
_subscription.Dispose();
}
}

如果您不想完全使用 Rx,另一种方法是这样做:

public class WaitForDelegate : IDisposable
{
private Action _detach;

public WaitForDelegate(Action<Action> add, Action<Action> remove)
{
Action handler = () => Console.WriteLine("trigger");
_detach = () => remove(handler);
add(handler);
}

public void Dispose()
{
if (_detach != null)
{
_detach();
_detach = null;
}
}
}

你可以这样调用它:

Action bar = () => Console.WriteLine("bar");

var wfd = new WaitForDelegate(h => bar += h, h => bar -= h);

bar();

这仍然是正确的输出。

关于c# - 将任何委托(delegate)作为参数的构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34701186/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com