7

を介してクラスのインスタンスをいくつか作成したいと思いますActivator.CreateInstance(...)。すべてのクラスは同じ抽象クラスを継承します。コンストラクターには 1 つのパラメーターがあります。

クラスとコンストラクターはpublicであってはなりません。

これは私がコードで欲しいものです(しかし得られません):

internal abstract class FooAbstract
{
    protected Bar MyProperty { get; set; }

    // Constructor is only need in concreat classes of FooAbstract
    protected FooAbstract(Bar barProperty)
    {
        MyProperty = barProperty;
    }
}

internal class Foo : FooAbstract
{
    // Internal is enough, public is not necessary
    internal Foo(Bar barProperty) 
        : base(barProperty)
    {
}

// Many more Foo´s ...

internal class Creator()
{
    private object CreateAFoo<T>() where T : FooAbstract
    {
        T someFoo = (T)Activator.CreateInstance(typeof(T), barProperty);
    }
}

しかし、これは Exception をスローしますConstructor on type 'Foo' not found

コンストラクターをFooAbstract and Fooに変更すると、publicすべてがうまくいきます (クラスはそのままですinternal!)。

したがって、パブリックアクセスが必要であることは理解できActivator.CreateInstance(...)ますが (彼はパッケージの外部からアクセスします)、内部クラスが残っている場合になぜこれが可能になるのでしょうか?

今まで、クラスが内部 コンストラクターがパブリックの場合、クラスが内部 コンストラクターも内部(一種の階層アクセス層)と同じになると思っていましたが、これは間違っているようです!

誰かがここで何が起こったのかを理解するのを手伝ってもらえますか? 内部クラスのパブリック コンストラクターが機能するのはなぜですか?

4

2 に答える 2

13

BindingFlagsリフレクションを見つけるには、 forを指定する必要があります。

(T)Activator.CreateInstance(typeof(T),
    BindingFlags.Instance | BindingFlags.NonPublic,
    null
    new object[] { barProperty },
    null);

さて、この場合、 ではないため、 を構築する必要があります。object[]params

マシュー・ワトソンが述べたように、リフレクションの仕組みを明確にする必要があります。そして、より具体的には修飾子です。それら[修飾子]は、実際の保護のために構築されていません。これらは、型を使用しているときに使用できる API を決定するために構築されています。

ただし、反射はモディファイアから直接機能します。それがpublic- の場合、リフレクションではpublicです。階層は関係ありません。リフレクションは実際にメンバーにアクセスできることを覚えておいてくださいprivate。私は知っています、私は以前にそのようなことをいくつかハックしなければなりませんでした。

さらに、コンストラクターは の修飾子を継承しませんclass。デフォルトのコンストラクター (定義しない場合にコンパイラーによって生成される) はalways publicです。

于 2013-10-15T12:09:59.047 に答える
1

アクティベーターはリフレクションを使用して、コンストラクターの適切なインスタンスを呼び出します。デフォルトでは、パブリック クラス メンバーのみを探している可能性があります。neoistheone で述べられているように、アクティベーター メソッド呼び出しでフラグを設定することで、コンストラクターを探す方法を変更できます。そのメソッドの逆コンパイルされたコードは次のようになります。

[SecuritySafeCritical]
[MethodImpl(MethodImplOptions.NoInlining)]
public static object CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture, object[] activationAttributes)
{
    if (type == null)
    {
        throw new ArgumentNullException("type");
    }
    if (type is TypeBuilder)
    {
        throw new NotSupportedException(Environment.GetResourceString("NotSupported_CreateInstanceWithTypeBuilder"));
    }
    if ((bindingAttr & (BindingFlags)255) == BindingFlags.Default)
    {
        bindingAttr |= (BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance);
    }
    if (activationAttributes != null && activationAttributes.Length > 0)
    {
        if (!type.IsMarshalByRef)
        {
            throw new NotSupportedException(Environment.GetResourceString("NotSupported_ActivAttrOnNonMBR"));
        }
        if (!type.IsContextful && (activationAttributes.Length > 1 || !(activationAttributes[0] is UrlAttribute)))
        {
            throw new NotSupportedException(Environment.GetResourceString("NotSupported_NonUrlAttrOnMBR"));
        }
    }
    RuntimeType runtimeType = type.UnderlyingSystemType as RuntimeType;
    if (runtimeType == null)
    {
        throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "type");
    }
    StackCrawlMark stackCrawlMark = StackCrawlMark.LookForMyCaller;
    return runtimeType.CreateInstanceImpl(bindingAttr, binder, args, culture, activationAttributes, ref stackCrawlMark);
}

RuntimeType は反映された型です。ここにスタック オーバーフローの質問があります: What's the difference between System.Type and System.RuntimeType in C#?

于 2013-10-15T12:29:55.443 に答える