カスタムEventArgs

イベント引数EventArgsにカスタム値を持たせるようにします。

もし認識が誤りがあれば、ご指摘をお願いします。

12/22 ちょこっと変えてみました。
12/27 ちょこっと変えてみました。ご指摘のあった部分を改良しました。

基底クラス系のクラス名AtepからはじまるAtep とは、新たに発見した万能 ~~細胞~~ 関数 Arbitary-Triggered Eventhandler of Pluripotencyの略です。Stupid-Triggered EventArgs of PluripotencyでStep でもいいかなと考えました。いっそのこと、Stimulus-Triggered Actions of PluripotencyでStapってのはどうでしょうか。 

要するにEventArgsを型引数クラスで継承して万能 ~~細胞~~ 関数化してるってことなんですよ。

次回は、この応用でランチャにタスクを実装した方式を掲載ます。
#本文
##基底関数群

```CSharp
public class AtepEventArgs<T> : EventArgs
{
		public T Value { get; private set; }
		public AtepEventArgs(T val)
		{
			Value = val;
		}
}
public delegate void EventHandler<TSender, TEventArgs>(TSender sender, TEventArgs e);
public interface ILauncher<T>
{
	event EventHandler<object, AtepEventArgs<T>> Raise;
}
public class AtepLauncher<T> : ILauncher<T>
{
		private T arg = default(T);
		public AtepLauncher()
		{
		}
		public AtepLauncher(T a)
		{
			this.arg = a;
		}
		public T Arg
		{
			get
			{
				return this.arg;
			}
			set
			{
				this.arg = value;
				OnChanged(this, new AtepEventArgs<T>(this.arg));
			}
		}
		// Delegate
		public event EventHandler<object, AtepEventArgs<T>> Raise;
		// Trigger
		public void OnChanged(object sender, AtepEventArgs<T> e)
		{
			if (Raise != null)
			{
				// Call the Event
				Raise(this, e);
			}
		}
}
public class AtepContainer<T>
{ 
		private List<ILauncher<T>> launcher;
		public AtepContainer()
		{
			this.launcher = new List<ILauncher<T>>();
		}

		public void Add(ILauncher<T> lchr)
		{
			lchr.Raise += new EventHandler<object, AtepEventArgs<T>>(HandleChanged);
			this.launcher.Add(lchr);
		}

		internal virtual void HandleChanged(object sender, AtepEventArgs<T> e)
		{
			// イベント発火, ここにoverride メソッドを記述
			Console.WriteLine("Received event. value={0}", e.Value);
		}
}
```
##目的別の関数
```CSharp
/// <summary>
/// (目的の)型
/// </summary>
public class MyItem
{
		public MyItem()
		{
		}
		public MyItem(int n, string s)
		{
			Number = n;
			TextMessage = s;
		}

		public int Number { get; set; }
		public string TextMessage { get; set; }
}

/// <summary>
/// (目的の)メイン
/// </summary>
internal class Test
{
		private static Test _instance { get; set; }
		public static Test GetInstance()
		{
			return _instance;
		}

		private static void Main(string[] args)
		{
			var myLauncher = new AtepLauncher<MyItem>();

			var container = new MyContainer();

			container.Add(myLauncher);

			myLauncher.Arg = new MyItem(1, "Item1");
			
			// Keep the console window open in debug mode.
			System.Console.WriteLine("Press any key to exit.");
			System.Console.ReadKey();

		}
}
```
##コード全体
```CSharp
using System;
using System.Collections.Generic;
using System.Threading;

/// <summary>
/// Note : 
/// Atep = Arbitary-Triggered Eventhandler of Pluripotency
/// </summary>
namespace RaiseBaseClassEventsTestPart3
{
	public class AtepEventArgs<T> : EventArgs
	{
		public T Value { get; private set; }
		public AtepEventArgs(T val)
		{
			Value = val;
		}
	}
	public delegate void EventHandler<TSender, TEventArgs>(TSender sender, TEventArgs e);
	public interface ILauncher<T>
	{
		event EventHandler<object, AtepEventArgs<T>> Raise;
	}
	public class AtepLauncher<T> : ILauncher<T>
	{
		private T arg = default(T);
		public AtepLauncher()
		{
		}
		public AtepLauncher(T a)
		{
			this.arg = a;
		}
		public T Arg
		{
			get
			{
				return this.arg;
			}
			set
			{
				this.arg = value;
				OnChanged(this, new AtepEventArgs<T>(this.arg));
			}
		}
		// Delegate
		public event EventHandler<object, AtepEventArgs<T>> Raise;
		// Trigger
		public void OnChanged(object sender, AtepEventArgs<T> e)
		{
			if (Raise != null)
			{
				// Call the Event
				Raise(this, e);
			}
		}
	}
	public class AtepContainer<T>
	{ 
		private List<ILauncher<T>> launcher;
		public AtepContainer()
		{
			this.launcher = new List<ILauncher<T>>();
		}

		public void Add(ILauncher<T> lchr)
		{
			lchr.Raise += new EventHandler<object, AtepEventArgs<T>>(HandleChanged);
			this.launcher.Add(lchr);
		}

		internal virtual void HandleChanged(object sender, AtepEventArgs<T> e)
		{
			// イベント発火, ここにoverride メソッドを記述
			Console.WriteLine("Received event. value={0}", e.Value);
		}
	}

	/// <summary>
	/// (目的の) ランチャコンテナ
	/// </summary>
	public class MyContainer : AtepContainer<MyItem>
	{
		internal override void HandleChanged(object sender, AtepEventArgs<MyItem> e)
		{
			if (e.Value == null)
				return;
			var item = e.Value as MyItem;
			var s = string.Format("({0}, {1})", item.Number.ToString(), item.TextMessage);
			Console.WriteLine("Received event." + s);
		}
	
	}
	
	/// <summary>
	/// (目的の)型
	/// </summary>
	public class MyItem
	{
		public MyItem()
		{
		}
		public MyItem(int n, string s)
		{
			Number = n;
			TextMessage = s;
		}

		public int Number { get; set; }
		public string TextMessage { get; set; }
	}

	/// <summary>
	/// (目的の)メイン
	/// </summary>
	internal class Test
	{
		private static Test _instance { get; set; }
		public static Test GetInstance()
		{
			return _instance;
		}

		private static void Main(string[] args)
		{
			var myLauncher = new AtepLauncher<MyItem>();

			var container = new MyContainer();

			container.Add(myLauncher);

			myLauncher.Arg = new MyItem(1, "Item1");
			
			// Keep the console window open in debug mode.
			System.Console.WriteLine("Press any key to exit.");
			System.Console.ReadKey();

		}
	}

}

```

#参考

* 方法 : 派生クラスから基本クラス イベントを発生させる (C# プログラミング ガイド)
https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/events/how-to-raise-base-class-events-in-derived-classes

* 方法: .NET Framework ガイドラインに準拠したイベントを発行する (C# プログラミング ガイド) https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/events/how-to-publish-events-that-conform-to-net-framework-guidelines

* 方法 : クラスにイベントを実装する 
https://msdn.microsoft.com/ja-jp/library/5z57dxz2(v=vs.110).aspx