は、イベントを作成して使用する方法の詳細についてHow to: Publish Events that Conform to .NET Framework Guidelines一読を持っています。私がここでその過程を歩みます。
イベントを定義するために必要な最初の部分は、使用されるイベントハンドラデリゲートです。このイベントで通知を受け取るすべての人に必要なメソッドシグネチャです。通常は、新しい代理人を自分で作成する必要はありません。既存のEventHandler
(または総称EventHandler<TEventArgs>
)代理人を使用する必要があります。イベントに関する他の引数を含める必要がない場合は、ジェネリックでないバージョンを使用します。それ以外の場合は、汎用バージョンを使用します。あなたのケースでは、イベントに関して必要なその他の引数はありませんので、非汎用のEventHandler
を使用する必要があります。
(引数に古い値や新しい値などの情報を含めるには、EventArgs
から派生した適切なクラスのジェネリックバージョンを使用してください。それを省略します。)
次の部分がイベントを定義することです。クラスのプロパティを定義するのと同じくらい簡単です。ここでの相違点は、event
キーワードを使用して、イベントを定義してから使用する代理人とイベントの名前を指定することです。プロパティーを変更するためのイベントの命名規則は通常、パターンがPropertyNameChanged
です。 Name
プロパティが変更されたときに発生するイベントが必要なので、名前をNameChanged
とする必要があります。
public event EventHandler NameChanged;
オプション(ただし強く推奨)ステップは、イベントを発生させるために使用される方法を定義することです。これにより、必要に応じてイベントを発生させやすくなります。通常の命名規則は、イベントの名前付け方法に似ています。今回は、OnEventName
です。だからここにOnNameChanged
と名づけましょう。これは通常、保護された仮想メソッドとして定義され、派生したクラスはこれを簡単にオーバーライドできます。関数の引数は、イベントに必要な引数でなければなりません。ここに引数がないので、署名に引数を付けずに残すことができます。
これをすべて実行すると、イベントハンドラを呼び出すだけです。それは単なるデリゲートなので、それを呼び出すだけです。しかし、最初にnull
であることを確認することを忘れないでください。これは、イベントハンドラが登録されていないことを意味します。ハンドラへの引数は、this
(イベントを発生させているオブジェクト)でなければなりません。この場合、引数はありませんが、 "空の" EventArgs
のインスタンスを返す必要があります。
protected virtual void OnNameChanged()
{
EventHandler nameChanged = NameChanged; // always a good idea to store in a local variable
if (nameChanged != null)
{
nameChanged(this, new EventArgs());
}
}
最後の部分は、あなたのプロパティでこれを配線することです。代入によってプロパティの値が変更される場合は、イベントを発生させたいでしょう。かなり簡単ですが、古い値が新しい値と異なるかどうかを確認するだけです。そうであれば、変更してイベントを起こします。それ以外の場合は、何もしないでください。
private string name;
public string Name
{
get { return name; }
set
{
if (!String.Equals(value, name)) // if the value gets changed...
{
name = value;
OnNameChanged(); // raise the event!!!
}
}
}
今、私たちはすべてのイベントで設定していることを、あなたは、このイベントのためにいくつかのハンドラを登録することができるようにしたいです。これを行うには、最初にName
の変更を待つPerson
のインスタンスが必要で、イベントの正しいシグネチャを持つイベント処理メソッドが必要です。このイベントはEventHandler
デリゲートを使用するように定義されているため、署名付きのメソッド(void NameChanged(object sender, EventArgs e)
)が必要です。引数はsender
で、イベントを発生させたオブジェクトです。この場合、オブジェクトはPerson
なので、変更したオブジェクトを取得して、必要に応じてプロパティを調べることができます。あなたは何でもいいと思っています。個人的に私が行くパターンは:InstanceName_EventName
です。だからこの場合、私はそれに名前をつけよう:person_NameChanged
。
static void person_NameChanged(object sender, EventArgs e)
{
Person person = (Person)sender; // cast back to a Person so we can see what's changed
Console.WriteLine("The name changed!");
Console.WriteLine("It is now: " + person.Name); // let's print the name
}
これが定義されたら、イベントにハンドラを追加すると、変更があった場合に通知されます。
person.NameChanged += person_NameChanged;
ハンドラを完全にクラス内にしたい場合は、クラス内でイベントを登録できます。それを外部に配線する必要はありません。あなたはコンストラクタからそれを行うことができます。 OnNameChanged()
イベントの発生方法にコードを追加することはお勧めしません。その方法は単にイベントを発生させるために予約する必要があります。
この特定の例では、ハンドラは静的であるため、単一のインスタンスに関連付けられていないことに注意してください。一般的にはPerson
であれば動作します。静的なので、this
を送信側のキャストが必要な方法で使用できないことに注意してください。それが静的であるかどうかは、最終的にあなた次第です。いずれの方法でも問題ありません。
だからすべて一緒にこれを置くために、これはあなたが何ができるかです:
class Person
{
public Person(string name = "John")
{
this.name = name;
this.NameChanged += builtin_NameChanged;
}
public string Name
{
get { return name; }
set
{
if (!String.Equals(value, name))
{
name = value;
OnNameChanged();
}
}
}
public event EventHandler NameChanged;
protected virtual void OnNameChanged()
{
EventHandler nameChanged = NameChanged;
if (nameChanged != null)
{
nameChanged(this, new EventArgs());
}
}
private static void builtin_NameChanged(object sender, EventArgs e)
{
Person person = (Person)sender;
Console.WriteLine("The name changed!");
Console.WriteLine("It is now: " + person.Name);
}
private string name;
}
class Program
{
static void Main(string[] args)
{
Person person = new Person();
person.Name = "Paul";
}
}