中堅プログラマーの備忘録

忘れっぽくなってきたので備忘録として・・・

【C#.net】文字列で指定したクラスのインスタンスを作成し、値を設定する

1.概要

同じような機能を持った関数が乱立するようなコードは
コードが長くなる原因となるため可読性が悪くなってしまい
バグの温床になりかねません。
同じような機能を持った関数は可能な限りまとめる必要があります。
そんな時、同じような関数を使って異なるオブジェクトの戻り値が取りたいことがあり
どうすればいいか悩んだ結果
Typeからインスタンスを作成できることを知り試してみました。

2.文字列からTypeの取得

【Type】を取得する場合私がよく使っていたのは【typeof】演算子を使った

Type type = typeof(Object);

上記のような方法です。


これを文字列から取得しようとすると

Type type = Type.GetType("System.Object");

となります。

3.Typeからインスタンスを作成する。

例えば下記のようなclassがあったとします。

public class States{
	public string name = "";
	public string age = "";
}

これのインスタンスを作成する場合

States states = new States();

のように作成します。
ですが今回は文字列からのインスタンスの作成なので
どのようにしたらいいかというと

【Type】さえ取得出来れば
【Activator】クラスの【CreateInstance】メソッドを使うことで
インスタンスが作成できます。

Type type = Type.GetType("namespace.States");
object obj = Activator.CreateInstance(type);

4.値を設定する

インスタンスの作成が出来ましたので
これの値を変更してみます。
変更するには【FieldInfo】クラスの【SetValue】メソッドを使用します。
下記では【name】の値を【hoge】に変更しています。

FieldInfo field = type.GetField("name");
field.SetValue(obj, "hoge");

このような形で値の変更が可能です。

5.やりたかったこと

大まかに言うと複数の異なるクラス型が存在し
それに対して同じような処理をしたかったのです。
何とか一つにまとめたかったので下記のようなコードにしました。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace sample
{
    class Program
    {
        static void Main(string[] args)
        {

            States states = (dynamic)MakeInstance("sample.States", "age", "37");
            Price price = (dynamic)MakeInstance("sample.Price", "apple", "200");
        }

        static public object MakeInstance(string className, string fieldName, string val)
        {
            Type type = Type.GetType(className);
            object obj = Activator.CreateInstance(type);
            FieldInfo field = type.GetField(fieldName);
            field.SetValue(obj, val);

            return obj;
        }
    }

    public class States
    {
        public string name = "chuken";
        public string age = "0";
    }

    public class Price
    {
        public string apple = "150";
        public string grape = "100";
    }
}


一つの関数で異なるクラスの値の変更が出来るようになりました。