web-dev-qa-db-ja.com

C#でプライベートコンストラクターを使用してオブジェクトをインスタンス化する方法は?

リフレクションか何かを使ってそうする例をどこかで見たのを確かに覚えています。これはSqlParameterCollectionと関係があり、ユーザーが作成することはできません(私が間違っていなければ)。残念ながら、もう見つけることができません。

誰かがこのトリックをここで共有できますか?私はそれが開発における有効なアプローチであると考えているわけではありませんが、これを行う可能性に非常に興味があります。

30
User
// the types of the constructor parameters, in order
// use an empty Type[] array if the constructor takes no parameters
Type[] paramTypes = new Type[] { typeof(string), typeof(int) };

// the values of the constructor parameters, in order
// use an empty object[] array if the constructor takes no parameters
object[] paramValues = new object[] { "test", 42 };

TheTypeYouWantToInstantiate instance =
    Construct<TheTypeYouWantToInstantiate>(paramTypes, paramValues);

// ...

public static T Construct<T>(Type[] paramTypes, object[] paramValues)
{
    Type t = typeof(T);

    ConstructorInfo ci = t.GetConstructor(
        BindingFlags.Instance | BindingFlags.NonPublic,
        null, paramTypes, null);

    return (T)ci.Invoke(paramValues);
}
41
LukeH

Activator.CreateInstanceのオーバーロードの1つを使用して、これを行うことができます: Activator.CreateInstance(Type type, bool nonPublic)

true引数にはnonPublicを使用します。 trueはパブリックまたは非パブリックのデフォルトコンストラクターと一致するため。 falseは、パブリックのデフォルトコンストラクターにのみ一致します。

例えば:

    class Program
    {
        public static void Main(string[] args)
        {
            Type type=typeof(Foo);
            Foo f=(Foo)Activator.CreateInstance(type,true);
        }       
    }

    class Foo
    {
        private Foo()
        {
        }
    }
59
Sean

これはあなたが求めていた質問ですか? プライベートシールクラスを持つActivator.CreateInstance

4
Jonathan Parker

クラスがあなたのものではない場合、これを防ぐためにAPIが意図的に作成されたように思われます。つまり、API作成者が意図したものではないアプローチである可能性があります。ドキュメントを見て、このクラスを使用するための推奨されるアプローチがあるかどうかを確認してください。

doがクラスを制御していて、このパターンを実装したい場合は、通常、クラスの静的メソッドを介して実装されます。これは、シングルトンパターンを構成する重要な概念でもあります。

例えば:

public PrivateCtorClass
{
    private PrivateCtorClass()
    {
    }

    public static PrivateCtorClass Create()
    {
        return new PrivateCtorClass();
    }
}

public SomeOtherClass
{
    public void SomeMethod()
    {
        var privateCtorClass = PrivateCtorClass.Create();
    }
}

SqlCommandParameterのものは良い例です。彼らはあなたがこのようなものを呼び出すことによってパラメータを作成することを期待しています:

var command = IDbConnnection.CreateCommand(...);
command.Parameters.Add(command.CreateParameter(...));

私の例は、コマンドパラメータプロパティの設定やパラメータ/コマンドの再利用を示していないため、優れたコードではありませんが、アイデアは得られます。

2
Neil Barnwell

Typeprivateまたはinternalの場合にも役立ちます。

 public static object CreatePrivateClassInstance(string typeName, object[] parameters)
    {
        Type type = AppDomain.CurrentDomain.GetAssemblies().
                 SelectMany(Assembly => Assembly.GetTypes()).FirstOrDefault(t => t.Name == typeName);
        return type.GetConstructors()[0].Invoke(parameters);
    }
1
Mr.B