如果你想使用Lazy<T>
定义的单例模式,下面是一个完整的例子。请注意,任何情况下,是static
,所以sender
参数包含对单个实例的引用:
public class EventArgs<T> : EventArgs
{
public EventArgs(T value)
{
this.Value = value;
}
public T Value { get; set; }
}
public class EventArgs2 : EventArgs
{
public int Value { get; set; }
}
internal static class Program
{
private static void Main(string[] args)
{
Singleton.Instance.MyEvent += (sender, e) => Console.WriteLine("MyEvent with empty parameter");
Singleton.Instance.MyEvent2 += (sender, e) => Console.WriteLine("MyEvent2 with parameter {0}", e.Value);
Singleton.Instance.MyEvent3 += (sender, e) => Console.WriteLine("MyEvent3 with parameter {0}", e.Value);
Singleton.Instance.Call();
Console.Read();
}
}
public sealed class Singleton
{
private static readonly Lazy<Singleton> lazy = new Lazy<Singleton>(() => new Singleton());
public static Singleton Instance { get { return lazy.Value; } }
/// <summary>
/// Prevents a default instance of the <see cref="Singleton"/> class from being created.
/// </summary>
private Singleton()
{
}
/// <summary>
/// Event without any associated data
/// </summary>
public event EventHandler MyEvent;
/// <summary>
/// Event with a specific class as associated data
/// </summary>
public event EventHandler<EventArgs2> MyEvent2;
/// <summary>
/// Event with a generic class as associated data
/// </summary>
public event EventHandler<EventArgs<int>> MyEvent3;
public void Call()
{
if (this.MyEvent != null)
{
this.MyEvent(this, EventArgs.Empty);
}
if (this.MyEvent2 != null)
{
this.MyEvent2(this, new EventArgs2 { Value = 12 });
}
if (this.MyEvent3 != null)
{
this.MyEvent3(this, new EventArgs<int>(12));
}
Console.Read();
}
}
编辑:
你也可以建立一些EventArgs<T1, T2>
,如果你需要传递两个值。最终,EventArgs<Tuple<>>
也将是可能的,但对于大于2点的值我会建立一个特定XXXEventArgs
类,而不是因为它更容易阅读XXXEventArgs.MyNamedBusinessProperty
比EventArgs<T1, T2, T3>.Value2
或EventArgs<Tuple<int, string, bool>>.Value.Item1
。
关于KISS/YAGNI:请记住(object sender, EventArgs e)
约定关于代码一致性。如果某些开发人员使用你的代码的处理程序连接到您的事件之一,我可以向你保证,他将只是爱的事实,你的事件定义为就像在BCL本身任何其他事件的定义,所以他立即知道如何正确使用你的代码。
甚至有有其他的优势不仅仅是代码的一致性/可读性:
我继承了我的自定义从EventArgs
XXXEventArgs
类,但你可以建立一些基地EventArgs
类,并从它继承。例如,请参见MouseEventArgs
以及从其继承的所有类。重复使用现有的类比提供具有5/6个相同属性的多个委托签名要好得多。例如:
public class MouseEventArgs : EventArgs
{
public int X { get; set; }
public int Y { get; set; }
}
public class MouseClickEventArgs : MouseEventArgs
{
public int ButtonType { get; set; }
}
public class MouseDoubleClickEventArgs : MouseClickEventArgs
{
public int TimeBetweenClicks { get; set; }
}
public class Test
{
public event EventHandler<MouseClickEventArgs> ClickEvent;
public event EventHandler<MouseDoubleClickEventArgs> DoubleClickEvent;
}
public class Test2
{
public delegate void ClickEventHandler(int X, int Y, int ButtonType);
public event ClickEventHandler ClickEvent;
// See duplicated properties below =>
public delegate void DoubleClickEventHandler(int X, int Y, int ButtonType, int TimeBetweenClicks);
public event DoubleClickEventHandler DoubleClickEvent;
}
的另一点是,使用EventArgs
可以简化代码的可维护性。想象一下以下情形:
public MyEventArgs : EventArgs
{
public string MyProperty { get; set; }
}
public event EventHandler<MyEventArgs> MyEvent;
...
if (this.MyEvent != null)
{
this.MyEvent(this, new MyEventArgs { MyProperty = "foo" });
}
...
someInstance.MyEvent += (sender, e) => SomeMethod(e.MyProperty);
如果你想添加一些MyProperty2
属性添加到MyEventArgs
,你能做到这一点,而无需修改所有现有的事件侦听器:
public MyEventArgs : EventArgs
{
public string MyProperty { get; set; }
public string MyProperty2 { get; set; }
}
public event EventHandler<MyEventArgs> MyEvent;
...
if (this.MyEvent != null)
{
this.MyEvent(this, new MyEventArgs { MyProperty = "foo", MyProperty2 = "bar" });
}
...
// I didn't change the event handler. If SomeMethod() doesn't need MyProperty2, everything is just fine already
someInstance.MyEvent += (sender, e) => SomeMethod(e.MyProperty);
这取决于项目。如果它是一个巨大的ddd项目,我会尽可能地保留这些(发送者和事件参数),即使它们没有被使用(以保留体系结构)。但如果它只是一个简单的控制台应用程序,它是不同的故事 – Fabjan