スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
当サイトは基本をすっ飛ばしてます。基本文法等は、@ITをどうぞ
カテゴリー: スポンサー広告

インスタンス生成あれこれ

ここでは、

public class ....等で定義される物を「クラス」
このクラスをnew xxxx()で作られた物を「インスタンス」

と呼ぶことにする。
このインスタンスを生成する方法には、大きくわけて、「newを使う」か、「リフレクションを使うか」がある。
・前者は、作成するクラスが、コーディング段階で具体的に決まっている場合、
・後者は、コーディング段階では決まらない(実行時に初めて決まる)場合
によく使われる。
で、3番目の選択肢として、「式木を使う」というのがC#4から(厳密には3から)出てきた。
式木を使う時の用途は、リフレクションを使う時のそれに近い。実行時に初めて型がわかる時。
これらのインスタンス生成に関する方法を何通りか実装して、比較する。
実装方法は違うけど、求める結果(Output)は同じ。インスタンスを生成すること。
方法に関する比較項目は、生成する際の時間的コスト≒「速さ」とする。
まず、以下のようなクラスを作る。

using System;
using System.Linq.Expressions;

namespace TawamureDays {

public static class ClassCreator<T> where T : new() {

/// <summary>
/// インスタンスを生成します。1
/// </summary>
/// <returns>インスタンス</returns>
public static T CreateInstance1() {
return new T();
}

/// <summary>
/// インスタンスを生成します。2
/// </summary>
/// <returns>インスタンス</returns>
public static T CreateInstance2() {
return (T)System.Activator.CreateInstance<T>();
}

/// <summary>インスタンス生成用のメソッド</summary>
private static Func<T> generateor_ =
Expression.Lambda<Func<T>>(Expression.New(typeof(T))).Compile();

/// <summary>
/// インスタンスを生成します。3
/// </summary>
/// <returns>インスタンス</returns>
public static T CreateInstance3() {
return generateor_();
}
}
}

以下の方法によりインスタンスを生成する。
1.Genericを使用して生成する。
2.リフレクションを使用して生成する。
3.式木によって動的にコーディング・コンパイルされたFunc<T>を使って生成する。
4.newで生成する。

生成するためのクラスを作る(ココらへんは適当)

namespace TawamureDays {

/// <summary>
/// 血液型を表すEnum
/// </summary>
public enum BloodType {
Unknown = 0,
TypeA,
TypeB,
TypeO,
TypeAB
}

/// <summary>
/// 作成されるクラス
/// </summary>
public class PersonalData {

/// <summary>
/// 名前を取得|設定します。
/// </summary>
public string FirstName { get; set; }

/// <summary>
/// 姓を取得|設定します。
/// </summary>
public string SecondName { get; set; }

/// <summary>
/// 年齢を取得|設定します。
/// </summary>
public int Age { get; set; }

/// <summary>
/// 体重を取得|設定します。
/// </summary>
public decimal Weight { get; set; }

/// <summary>
/// 身長を取得|設定します。
/// </summary>
public decimal Height { get; set; }

/// <summary>
/// 血液型を取得|設定します。
/// </summary>
public BloodType BloodType { get; set; }
}
}

生成するための実装

class Program {

/// <summary>
/// ストップウォッチとなるクロージャを取得します。
/// </summary>
/// <returns>ストップウォッチ的クロージャ</returns>
public static Func<DateTime> StopWatch() {
var start = DateTime.Now;
return () => new DateTime(DateTime.Now.Ticks - start.Ticks);
}

public static void Main(string[] args) {
var watch = StopWatch();

for (int i = 0; i < 10000000; i++) {
//一千万回生成
var newData =
ClassCreator<PersonalData>.CreateInstance1();
//ClassCreator<PersonalData>.CreateInstance2();
//ClassCreator<PersonalData>.CreateInstance3();
//new PersonalData();
}

var cost = watch();

Console.WriteLine("cost : " + cost.ToString("HH:mm:ss fff"));
}
}

↑で呼び出すメソッドを切り替えていく。

実行環境:
CPU:Intel Core i5 2.53GHz
メモリ:4GB

結果(1千万回生成):
本来は、何個かサンプリングして平均を取るんだけど、めんどいので3回くらいの平均値。
1.Genericを使用して生成する。...1秒433
2.リフレクションを使用して生成する。...1秒373
3.式木によって動的にコーディング・コンパイルされたFunc<T>を使って生成する。...0秒550
4.newで生成する。...0秒144

考察:
・new T()で生成するのと、リフレクションを使った時のコストが大差ない。
 昔、どこかの記事にあったんだけど、new T()って、実は裏でリフレクションを使っているらしい。
 リンクをどこかにやってしまったので貼れないけどOrz。
・式木を使った時のコストがリフレクション時の半分になっている。性能的には倍という事か。
 ※ただし、Compileメソッドの実行を一回だけにした上での結果。毎回コンパイルすると、一番の鈍亀になる。
・それでもnewにはかなわない(当たり前)。
・一千万繰り返して、ようやく出てくるような差(それも0.5秒程度)なので、相対的に見て性能が劣るというだけの話になるのかな。
・クライアントのスペックさえ十分に確保できるなら、気にしないでも良いレベルかもしれない。
速くできるなら、それにこした事はないので、仕事では、式木での生成を利用中。コーディング段階でわかるなら、当然newを使うけどね。
スポンサーサイト
当サイトは基本をすっ飛ばしてます。基本文法等は、@ITをどうぞ
カテゴリー: C# | コメント: 0 | トラックバック: 0


この記事へのコメント

コメントの投稿

非公開コメント


サイドバー背後固定表示サンプル

当ブログに書かれたソースコードは流用自由です。

バグ、スペルミス等はありうる事です。

ご利用の際は自己責任でお願いしますm(_ _)m

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。