7

我想通过创建一些类实例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);
    }
}

但这会引发 Exception Constructor on type 'Foo' not found

当我更改构造函数时,FooAbstract 一切 都会好起来的(类保持不变!)。Foopublicinternal

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

到目前为止,我认为当类是内部的 并且 构造函数是公共的时,它与类是内部的 并且 构造函数也是内部的(对于某种分层访问层)......但这似乎是错误的!

有人可以帮我理解这里发生了什么 - 为什么内部类中的公共构造函数可以工作?

4

2 回答 2

13

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

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

现在,在这种情况下,您确实需要构建一个,object[]因为它不是一个params.

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

然而,反射直接作用于修改器。如果是public- 那么通过反射它是public. 等级无关紧要。请记住,反射实际上可以访问private成员。我知道,我以前不得不破解一些类似的东西。

此外,构造函数不继承class. 默认构造函数——如果你没有定义它由编译器生成——总是 public.

于 2013-10-15T12:09:59.047 回答
1

激活器使用反射来调用构造函数的正确实例。默认情况下,它可能只寻找公共类成员。正如 neoistheone 所说,您可以通过在 activator 方法调用上设置标志来更改它寻找构造函数的方式。该方法的反编译代码如下所示。

[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 是一种反射类型,这里有一个关于它的堆栈溢出问题: C# 中 System.Type 和 System.RuntimeType 有什么区别?

于 2013-10-15T12:29:55.443 回答