内部类和公共构造函数 - 为什么它与Activator.CreateInstance一起使用?

时间:2013-10-15 12:02:26

标签: c# .net constructor access-modifiers activator

我想通过Activator.CreateInstance(...)创建一些类的实例。所有类都继承相同的抽象类。构造函数有一个参数。

类和构造函数不应公开。

这就是我想要的代码(但不是得到):

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);
    }
}

但这会抛出异常Constructor on type 'Foo' not found

当我将FooAbstract Foo的构造函数更改为public时,一切都会正常(类保持internal!)。

所以我可以理解Activator.CreateInstance(...)需要公共访问(他来自包外),但为什么剩下的内部类可以实现呢?

到目前为止,我认为当类是内部 构造函数是公共的时,它将与类是内部< / em> 构造函数也是内部(对于一种层次化的访问层)...但这似乎是错误的!

有人可以帮我理解这里发生了什么 - 为什么内部班级的公共建设者有效?

2 个答案:

答案 0 :(得分:10)

您需要为反射指定BindingFlags才能找到它:

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

现在,在这种情况下,您需要来构建object[],因为它不是params

正如Matthew Watson所说,我应该澄清反思的运作方式。也许更具体的修饰语。它们[修饰符]不是为真正的保护而构建的。它们用于确定在使用类型时可用的API。

然而,

反射,直接直接关闭修饰符。如果它是public - 则使用反射public。层次结构无关紧要。请记住,反射实际上可以访问private个成员。我知道,我之前不得不破解类似的东西。

此外,构造函数不继承class的修饰符。默认构造函数 - 如果你没有定义它,由编译器生成 - 总是 public

答案 1 :(得分: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#?