「トップページ/CSHARP/Class」の編集履歴(バックアップ)一覧はこちら

トップページ/CSHARP/Class」(2010/12/27 (月) 13:07:58) の最新版変更点

追加された行は緑色になります。

削除された行は赤色になります。

|&big(){クラス}| #contents() ---- *クラスの実装 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の実装 &s(){よく見かけるサンプルコードだが、Dispose(bool)のdisposing引数の意味がいまいち。} &s(){たぶん、デストラクタの後にGCにより解放されるので、あえて自分では解放しないのだろう。} &s(){わざわざ分けなくても、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("フル名前空間");
|&big(){クラス}| #contents() ---- *クラスの実装 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の実装 &s(){よく見かけるサンプルコードだが、Dispose(bool)のdisposing引数の意味がいまいち。} &s(){たぶん、デストラクタの後にGCにより解放されるので、あえて自分では解放しないのだろう。} &s(){わざわざ分けなくても、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];

表示オプション

横に並べて表示:
変化行の前後のみ表示: