クラスの実装
1.クラス先頭に、クラス名の文字列定数を定義する
ログ等でクラス名が必要なときに、リフレクションを使わなくてもよいというメリットがある。
public class Foo
{
protected virtual string ClassName
{
get
{
return PackedSocket.className;
}
}
private const string className = "Foo"; // <-- クラス名の文字列
}
public class Bar
{
protected override string ClassName
{
get
{
return Bar.className;
}
}
private const string className = "Bar";
}
9.排他制御変数の定義(必要な場合のみ)
常に同じ名前で定義することにより、再利用性が高まる
public LockObject
{
get
{
return lockObject;
}
}
private readonly object lockObject = new object();
または、
public LockRW
{
get
{
return lockRW;
}
}
private readonly ReaderWriterLock lockRW = new ReaderWriterLock();
9.Disposeインターフェイスの実装(必要な場合のみ)
Disposeの実装
よく見かけるサンプルコードだが、Dispose(bool)のdisposing引数の意味がいまいち。
たぶん、デストラクタの後にGCにより解放されるので、あえて自分では解放しないのだろう。
わざわざ分けなくても、disposedメンバによる判定だけでもよさそうだが……。
実験の結果、2重解放の防止であった。デストラクタが呼ばれた時点で、既にマネージドリソースは解放されている。
// 解放後に呼ぶと例外を出す
// throw new ObjectDisposedException(this.GetType().FullName);
public class Foo : IDisposable
{
/// <summary>disposedが呼ばれたかどうか(true:呼ばれた)</summary>
private bool disposed = false;
/// <summary>Disposeインターフェイス</summary>
public void Dispose()
{
// マネージドリソースを解放する
Dispose(true);
// デストラクタは呼ばれなくなる
GC.SuppressFinalize(this);
}
/// <summary>内部:Disposeインターフェイス</summary>
/// <param name="disposing">マネージドリソースを解放する(true:解放する)</param>
/// <remarks>クラスがsealedでない場合はvirtualにしておく</remarks>
protected virtual Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
// ここでマネージドリソースを廃棄
}
// ここでアンマネージドリソースの後始末
}
disposed = true;
}
/// <summary>デストラクタ<br/>Disposeが呼ばれたときは、実行されない</summary>
~Foo()
{
// マネージドリソースは既に解放済みなので、解放処理を実行しない
Dispose(false);
}
}
IDisposableクラスの継承
void Dispose(bool)のみ実装すればよい。また、bool disposedは、基底クラスとは別に持つ必要がある。
public class DelivedType : IDisposableClass
{
/// <summary>disposedが呼ばれたかどうか(true:呼ばれた)</summary>
private bool disposed;
/// <summary>内部:Disposeインターフェイス</summary>
/// <param name="disposing">マネージドリソースを解放する(true:解放する)</param>
/// <remarks>クラスがsealedでない場合はvirtualにしておく</remarks>
protected override void Dispose(bool disposing)
{
try
{
if ( !this.disposed )
{
if ( disposing )
{
// ここでマネージドリソースのリリース処理
}
// ここで、アンマネージドリソースのリリース処理
}
disposed = true;
}
finally
{
base.Dispose(disposing);
}
}
}
コンストラクタ・デストラクタとDisposeの実験
実行結果
new Foo::Constructor 基底クラスのコンストラクタ
new Bar::Constructor 継承クラスのコンストラクタ
new Dummy::Constructor メンバのクラスのコンストラクタ
---- <--ここからusing
using Foo::Constructor
using Bar::Constructor
using Dummy::Constructor
using Foo::Dispose
using Bar::Dispose(True)
解放 Disposeメソッド内の、マネージドリソース解放部
using Foo::Dispose(True)
.... <--ここがmainの終わり
using Dummy::Destructor
new Dummy::Destructor !先に内部のマネージドクラスのデストラクタが呼ばれている
new Bar::Destructor
new Foo::Destructor
new Bar::Dispose(False)
new Foo::Dispose(False)
using System;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Bar bar = new Bar("new ");
Console.WriteLine("----");
using (var b = new Bar("using"))
{
}
Console.WriteLine("....");
}
}
public class Foo : IDisposable
{
protected string name;
public Foo(string s)
{
this.name = s;
Console.WriteLine(name + " Foo::Constructor");
}
/// <summary>disposedが呼ばれたかどうか(true:呼ばれた)</summary>
private bool disposed = false;
/// <summary>Disposeインターフェイス</summary>
public void Dispose()
{
Console.WriteLine(name + " Foo::Dispose");
// マネージドリソースを解放する
Dispose(true);
// デストラクタは呼ばれなくなる
GC.SuppressFinalize(this);
}
/// <summary>内部:Disposeインターフェイス</summary>
/// <param name="disposing">マネージドリソースを解放する(true:解放する)</param>
protected virtual void Dispose(bool disposing)
{
Console.WriteLine(name + " Foo::Dispose({0})", disposing);
if (!this.disposed)
{
if (disposing)
{
// ここでマネージドリソースを廃棄
}
// ここでアンマネージドリソースの後始末
}
disposed = true;
}
/// <summary>デストラクタ<br/>
/// Disposeが呼ばれたときは、実行されない</summary>
~Foo()
{
Console.WriteLine(name + " Foo::Destructor");
// マネージドリソースは既に解放済みなので、解放処理を実行しない
Dispose(false);
}
}
public class Bar : Foo
{
public Bar(string s)
: base(s)
{
Console.WriteLine(name + " Bar::Constractor");
Inner inner = new Inner(name);
}
Inner inner;
/// <summary>disposedが呼ばれたかどうか(true:呼ばれた)</summary>
private bool disposed;
/// <summary>内部:Disposeインターフェイス</summary>
/// <param name="disposing">マネージドリソースを解放する(true:解放する)</param>
/// <remarks>クラスがsealedでない場合はvirtualにしておく</remarks>
protected override void Dispose(bool disposing)
{
Console.WriteLine(name + " Bar::Dispose({0})", disposing);
try
{
if (!this.disposed)
{
if (disposing)
{
// ここでマネージドリソースのリリース処理
Console.WriteLine("解放");
inner = null;
}
// ここで、アンマネージドリソースのリリース処理
}
disposed = true;
}
finally
{
base.Dispose(disposing);
}
}
~Bar()
{
Console.WriteLine(name + " Bar::Destructor");
}
class Inner
{
string name;
public Inner(string s)
{
name = s;
Console.WriteLine(name + " Dummy::Constructor");
}
~Inner()
{
Console.WriteLine(name + " Dummy::Destructor");
}
}
}
}
ロガーの定義
無条件で定義しておく(ロギングを参照)
AssemblyInfo.csの修正も忘れないように…
private static readonly ILog Logger = LogManager.GetLogger("フル名前空間");
private static readonly ILog LogDump = LogManager.GetLogger("フル名前空間");
配列プロパティ(インデクサ付き)
Foo foo = new Foo
int count = foo.Bar.Count;
int data3 = foo.Bar[3];
最終更新:2010年12月27日 13:07