「アダプター」を使用して、このイベントを他の多くのイベントから抽象化することもできます。
たとえば、私のプロジェクトの1つから...
#region Copyright
/*
This file came from Managed Media Aggregation, You can always find the latest version @ https://net7mma.codeplex.com/
*/
#endregion
namespace Media.Sockets
{
#region NetworkConnection
/// <summary>
/// Represents a <see cref="Connection"/> specific to the Network.
/// </summary>
public class NetworkConnection : Connection, Common.ISocketReference
{
#region NetworkConnectionState
[System.Flags]
protected enum NetworkConnectionState : long
{
None = 0,
Initialized = 1,
Bound = 2,
Connected = 4,
}
#endregion
#region Fields
/// <summary>
/// Created in <see cref="CreateWaitHandle"/>, Disposed in <see cref="Dispose"/>.
/// </summary>
Common.Extensions.WaitHandle.DisposableWaitHandle WaitHandle;
/// <summary>
/// The date and time when the Connection was started.
/// </summary>
protected System.DateTime LasRemoteConnectionStartedDateTime;
/// <summary>
/// The date and time when the Connection was started.
/// </summary>
protected System.DateTime LastRemoteConnectionCompletedDateTime;
#endregion
#region Properties
/// <summary>
/// Gets the amount of time taken to connect to the <see cref="RemoteEndPoint"/>
/// </summary>
public System.TimeSpan RemoteConnectionTime { get { return LastRemoteConnectionCompletedDateTime - LasRemoteConnectionStartedDateTime; } }
/// <summary>
/// The <see cref="System.Net.NetworkInformation.NetworkInterface"/> assoicated with the NetworkConnection.
/// </summary>
public System.Net.NetworkInformation.NetworkInterface NetworkInterface { get; protected set; }
/// <summary>
/// The <see cref="System.Net.Sockets.Socket"/> assoicated with the NetworkConnection.
/// </summary>
public System.Net.Sockets.Socket ConnectionSocket { get; protected set; }
/// <summary>
/// Indicates if the NetworkConnection has a <see cref="NetworkInterface"/> which is not null.
/// </summary>
public bool HasNetworkInterface { get { return NetworkInterface != null; } }
/// <summary>
/// The <see cref="System.Net.EndPoint"/> from which this NetworkConnection connects to the <see cref="RemoteEndPoint"/>
/// </summary>
public System.Net.EndPoint LocalEndPoint { get; protected set; }
/// <summary>
/// Indicates if this NetworkConnection has a <see cref="LocalEndPoint"/> which is not null.
/// </summary>
public bool HasLocalEndPoint { get { return LocalEndPoint != null; } }
/// <summary>
/// The <see cref="System.Net.EndPoint"/> from which this NetworkConnection is connected to via the <see cref="LocalEndPoint"/>
/// </summary>
public System.Net.EndPoint RemoteEndPoint { get; protected set; }
/// <summary>
/// Indicates if this NetworkConnection has a <see cref="RemoteEndPoint"/> which is not null.
/// </summary>
public bool HasRemoteEndPoint { get { return RemoteEndPoint != null; } }
/// <summary>
/// Indicates the <see cref="NetworkConnectionState"/> assoicated with this NetworkConnection
/// </summary>
protected NetworkConnectionState NetworkConnectionFlags
{
get { return (NetworkConnectionState)Flags; }
set { Flags = (long)value; }
}
#endregion
#region Constructor
public NetworkConnection()
: base() { }
public NetworkConnection(string name, bool shouldDispose)
: base(name, shouldDispose) { }
public NetworkConnection(System.Net.Sockets.Socket existingSocket, bool ownsHandle, bool shouldDispose)
: this("System.Net.Socket-" + ownsHandle.ToString(), shouldDispose)
{
if (existingSocket == null) throw new System.ArgumentNullException("existingSocket");
//Assign the ConnectionSocket
ConnectionSocket = existingSocket;
//Flag Initialized.
FlagInitialized();
//Assign the NetworkInterface
NetworkInterface = Common.Extensions.NetworkInterface.NetworkInterfaceExtensions.GetNetworkInterface(ConnectionSocket);
//Create a WaitHandle
CreateWaitHandle(ConnectionSocket.Handle, ownsHandle);
//Check IsBound
if (ConnectionSocket.IsBound)
{
//Flag Bound.
FlagBound();
//Serialize and Assign LocalEndPoint
LocalEndPoint = existingSocket.LocalEndPoint;
}
//Check Connected
if (ConnectionSocket.Connected)
{
//Sample the clock
LasRemoteConnectionStartedDateTime = System.DateTime.UtcNow;
//Serialize and Assign RemoteEndPoint
RemoteEndPoint = existingSocket.RemoteEndPoint;
//Call Connect to FlagConnected and call base logic.
Connect();
//Sample the clock
LastRemoteConnectionCompletedDateTime = System.DateTime.UtcNow;
}
}
#endregion
#region NetworkChange Event Handlers
void NetworkChange_NetworkAvailabilityChanged(object sender, System.Net.NetworkInformation.NetworkAvailabilityEventArgs e)
{
Refresh();
}
void NetworkChange_NetworkAddressChanged(object sender, System.EventArgs e)
{
Refresh();
}
#endregion
#region Bound
protected void FlagBound()
{
//Indicate Bound
Flags |= (long)NetworkConnectionState.Bound;
}
protected void UnFlagBound()
{
//Indicate not Bound
Flags &= (long)NetworkConnectionState.Bound;
}
#endregion
#region Initialize
protected void FlagInitialized()
{
//Indicate Connected
Flags |= (long)NetworkConnectionState.Initialized;
}
protected void UnFlagInitialized()
{
//Indicate Not Connected
Flags &= (long)NetworkConnectionState.Initialized;
}
public virtual void Initialize(bool registerForEvents)
{
//Check not already Initialized.
if (false == NetworkConnectionFlags.HasFlag(NetworkConnectionState.Initialized))
{
//Indicate Initialized
FlagInitialized();
if (registerForEvents)
{
//Attach events
System.Net.NetworkInformation.NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;
System.Net.NetworkInformation.NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged;
}
}
}
#endregion
#region Refresh
public override void Refresh()
{
base.Refresh();
}
#endregion
#region CreateConnectionSocket
public void CreateConnectionSocket(System.Net.Sockets.AddressFamily addressFamily, System.Net.Sockets.SocketType socketType, System.Net.Sockets.ProtocolType protocolType)
{
if (ConnectionSocket == null)
{
ConnectionSocket = new System.Net.Sockets.Socket(addressFamily, socketType, protocolType);
CreateWaitHandle(ConnectionSocket.Handle, true);
}
}
#endregion
#region CreateWaitHandle
public void CreateWaitHandle(System.IntPtr handle, bool ownsHandle)
{
if (WaitHandle == null)
{
WaitHandle = new Common.Extensions.WaitHandle.DisposableWaitHandle(handle, ownsHandle);
}
}
#endregion
#region Connect
protected void FlagConnected()
{
//Indicate Connected
Flags |= (long)NetworkConnectionState.Connected;
}
protected void UnFlagConnected()
{
//Indicate Not Connected
Flags &= (long)NetworkConnectionState.Connected;
}
public override void Connect()
{
//Check not already Connected.
if (false == NetworkConnectionFlags.HasFlag(NetworkConnectionState.Connected))
{
//Check IsEstablished
if (IsEstablished) return;
if (NetworkInterface == null) throw new System.InvalidOperationException("NetworkInterface must be assigned before calling Connect.");
if (LocalEndPoint == null) throw new System.InvalidOperationException("LocalEndPoint must be assigned before calling Connect.");
if (RemoteEndPoint == null) throw new System.InvalidOperationException("RemoteEndPoint must be assigned before calling Connect.");
//Set established
base.Connect();
//Indicate Connected
FlagConnected();
//Refresh the connection
Refresh();
}
}
/// <summary>
/// Creates the <see cref="CreateConnectionSocket"/> using the specified options and connects the socket.
/// Assigns <see cref="LocalEndPoint"/> and <see cref="RemoteEndPoint"/>
/// </summary>
/// <param name="addressFamily"></param>
/// <param name="socketType"></param>
/// <param name="protocolType"></param>
/// <param name="addressList"></param>
/// <param name="port"></param>
public virtual void Connect(System.Net.Sockets.AddressFamily addressFamily, System.Net.Sockets.SocketType socketType, System.Net.Sockets.ProtocolType protocolType, System.Net.IPAddress[] addressList, int port)
{
try
{
//Create the socket
CreateConnectionSocket(addressFamily, socketType, protocolType);
//Sample the clock
LasRemoteConnectionStartedDateTime = System.DateTime.UtcNow;
//Connect the socket
ConnectionSocket.Connect(addressList, port);
//Sample the clock
LastRemoteConnectionCompletedDateTime = System.DateTime.UtcNow;
}
finally
{
//Assign the NetworkInterface
NetworkInterface = Common.Extensions.NetworkInterface.NetworkInterfaceExtensions.GetNetworkInterface(ConnectionSocket);
//Assign the LocalEndPoint
LocalEndPoint = (System.Net.IPEndPoint)ConnectionSocket.LocalEndPoint;
//Assign the RemoteEndPoint
RemoteEndPoint = (System.Net.IPEndPoint)ConnectionSocket.RemoteEndPoint;
//Call Connect to FlagConnected and call base logic.
Connect();
}
}
#endregion
#region Disconnect
public virtual void Disconnect(bool allowReuse = false)
{
//Check not already Connected.
if (((NetworkConnectionState)Flags).HasFlag(NetworkConnectionState.Connected))
{
ConnectionSocket.Disconnect(allowReuse);
base.Disconnect();
UnFlagConnected();
Refresh();
}
}
public override void Disconnect()
{
Disconnect(false);
}
#endregion
#region Dispose
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
using (WaitHandle)
{
System.Net.NetworkInformation.NetworkChange.NetworkAddressChanged -= NetworkChange_NetworkAddressChanged;
System.Net.NetworkInformation.NetworkChange.NetworkAvailabilityChanged -= NetworkChange_NetworkAvailabilityChanged;
ConnectionSocket = null;
LocalEndPoint = RemoteEndPoint = null;
NetworkInterface = null;
}
}
#endregion
System.Collections.Generic.IEnumerable<System.Net.Sockets.Socket> Common.ISocketReference.GetReferencedSockets()
{
yield return ConnectionSocket;
}
}
#endregion
}
「接続」基本クラスが必要な場合は、これを参照できます
#region Copyright
/*
This file came from Managed Media Aggregation, You can always find the latest version @ https://net7mma.codeplex.com/
Julius.Friedman@gmail.com / (SR. Software Engineer ASTI Transportation Inc. http://www.asti-trans.com)
* v//
*/
#endregion
namespace Media.Sockets
{
#region Connection
/// <summary>
/// Provides a base class to facilitate the concept of a Connection.
/// </summary>
public abstract class Connection : Common.BaseDisposable
{
#region Statics
/// <summary>
/// A string with the format of:
/// `TypeName Id Flags Name`
/// </summary>
const string FormatString = "{0} {1} ({2}) {3}";
#endregion
#region Properties
/// <summary>
/// The unique identifier assoicated with this instance.
/// </summary>
public readonly System.Guid Id = System.Guid.NewGuid();
/// <summary>
/// The date and time the instance was created.
/// </summary>
public readonly System.DateTime Created = System.DateTime.UtcNow;
/// <summary>
/// The name assigned to this instance.
/// </summary>
public readonly string Name;
/// <summary>
/// Indicates if <see cref="Disconnect"/> will be called when disposing.
/// </summary>
public bool IsPersistent
{
get
{
return ShouldDispose == false;
}
set
{
ShouldDispose = value == false;
}
}
/// <summary>
/// Provided for derived implementations
/// </summary>
protected long Flags { get; set; }
/// <summary>
/// Indicates if the Connection is established.
/// </summary>
public virtual bool IsEstablished { get; protected set; }
/// <summary>
/// The date and time the Connection was established.
/// </summary>
public System.DateTime EstablishedDateTime { get; protected set; }
/// <summary>
/// The amount of time the connection has been established.
/// </summary>
public System.TimeSpan TimeEstablished { get { return IsEstablished ? System.DateTime.UtcNow - EstablishedDateTime : System.TimeSpan.Zero; } }
#endregion
#region Connect
/// <summary>
/// If <see cref="IsDisposed"/> is false, Sets <see cref="IsEstablished"/> to true.
/// </summary>
public virtual void Connect()
{
if (IsDisposed) return;
EstablishedDateTime = System.DateTime.UtcNow;
IsEstablished = true;
}
#endregion
#region Disconnect
/// <summary>
/// If <see cref="IsDisposed"/> is false, Sets <see cref="IsEstablished"/> to false.
/// </summary>
public virtual void Disconnect()
{
if (IsDisposed) return;
IsEstablished = false;
}
#endregion
#region Refresh
/// <summary>
/// Refreshes the details of the Connection.
/// Throws a <see cref="System.ObjectDisposedException"/> if <see cref="IsDisposed"/> is true.
/// </summary>
public virtual void Refresh()
{
CheckDisposed();
}
#endregion
#region Dispose
/// <summary>
/// If <see cref="IsDisposed"/> is True the call returns immediately.
/// Calls <see cref="Disconnect"/> if <see cref="IsPersistent"/> is False and calls <see cref="Common.BaseDisposable.Dispose"/>
/// </summary>
public override void Dispose()
{
if (IsDisposed) return;
if (false == IsPersistent) Disconnect();
base.Dispose();
}
#endregion
#region Constructor
public Connection(string name, bool shouldDispose)
: base(shouldDispose)
{
Name = name;
}
public Connection()
: this(string.Empty, true) { }
#endregion
#region ToString
public override string ToString()
{
return string.Format(FormatString, GetType().Name.ToString(), Id.ToString(), Flags, Name);
}
#endregion
}
#endregion
}