クラス



クラスの実装

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