我想从事件中重复代表重复的代表。所以我写了下面的代码。它工作正常。我的申请是一个时间批评的应用程序。是否有任何其他优化的mechansim实现相同。请帮帮我
public void FireEvent()
{
Dictionary<Delegate, Delegate> dic = new Dictionary<Delegate, Delegate>();
Delegate[] m = this.Paused.GetInvocationList();
foreach (Delegate d in m)
{
Delegate dout;
if (dic.TryGetValue(d, out dout))
{
continue;
}
else
{
dic.Add(d, d);
}
d.DynamicInvoke(new object[2] { this, null });
}
}
答案 0 :(得分:10)
如果这确实是一个时间关键的应用程序,我强烈建议您更改代码。
Dictionary<Delegate, Delegate>
。这很浪费。DynamicInvoke
,其开始时的性能低于常规调用。object[]
作为参数传递给DynamicInvoke
来电,再次每次 FireEvent
来电。这对于已建立的事件处理机制来说有点堕落。
在我看来,这是一个更好的解决方案:不是让这个FireEvent
方法向后弯曲以忽略已添加的重复委托,为什么不阻止委托多次附加到事件中第一名?
private HashSet<EventHandler> _pausedHandlers = new HashSet<EventHandler>();
public event EventHandler Paused
{
add // will not add duplicates
{ _pausedHandlers.Add(value); }
remove
{ _pausedHandlers.Remove(value); }
}
然后,您可以简单地以更加传统,经过时间考验的方式举办活动,确信没有任何代表多次加入该活动。
protected void OnPaused()
{
foreach (EventHandler handler in _pausedHandlers)
{
try
{
handler(this, EventArgs.Empty);
}
catch
{
// up to you what to do here
}
}
}
对这个答案的评论已经阐明了代表平等问题,我觉得将这个答案包括在内是有益的。如果您有兴趣,请查看我编写的以下代码示例,以使此主题更容易理解。
class Program
{
static void Main(string[] args)
{
// Even though the code for FirstHandler and SecondHandler is the same,
// they will not (nor should they) be considered equal for the purpose
// of detecting duplicates.
EventHandler handler1 = FirstHandler;
EventHandler handler2 = SecondHandler;
// Since handler2 and handler3 point to the same method, on the other
// hand, they will (and ought to) be treated as equal.
EventHandler handler3 = SecondHandler;
// So this prints 'False'...
Console.WriteLine(handler1.Equals(handler2));
// ...and this prints 'True'.
Console.WriteLine(handler2.Equals(handler3));
// Now take a look at the code for SetAnonymousHandler below. The
// method accepts an EventHandler by reference and compares it for
// equality to a delegate pointing to an anoymous lambda method. If the
// two are equal, it sets the EventHandler to this new delegate and
// returns true; otherwise it returns false.
// This prints 'True', as handler1 is not equal to the delegate
// declared within the SetAnonymousHandler method.
Console.WriteLine(SetAnonymousHandler(ref handler1));
// HOWEVER, now it prints 'False' for a simple reason: the delegate
// declared in SetAnonymousHandler points to an actual method. The fact
// that it is an anonymous method simply means that the compiler
// automatically generates a "proper" method for it in IL (to see what
// I mean, read the comment at the bottom of this class). So now,
// as with handler2 and handler3 above, handler1 and the delegate
// declared in SetAnonymousHandler point to the same method and are
// therefore equal; the method returns false.
Console.WriteLine(SetAnonymousHandler(ref handler1));
Console.ReadLine();
}
static void FirstHandler(object sender, EventArgs e)
{
Console.WriteLine("Testing");
}
static void SecondHandler(object sender, EventArgs e)
{
Console.WriteLine("Testing");
}
static bool SetAnonymousHandler(ref EventHandler handler)
{
EventHandler anonymous = (sender, e) => Console.WriteLine("Testing");
if (!handler.Equals(anonymous))
{
handler = anonymous;
return true;
}
else
{
return false;
}
}
// Note: When the above method is compiled, the C# compiler generates code
// that would look something like this if translated back from IL to C#
// (not exactly, but the point is just to illustrate that an anoymous
// method, after compilation, is really just like a "proper"
// -- i.e., non-anonymous -- method).
//static bool SetAnonymousHandler(ref EventHandler handler)
//{
// EventHandler anonymous = SetAnonymousHandler_Anonymous;
// if (handler.Equals(anonymous))
// {
// handler = anonymous;
// return true;
// }
// else
// {
// return false;
// }
//}
//static void SetAnonymousHandler_Anonymous(object sender, EventArgs e)
//{
// Console.WriteLine("Testing");
//}
}