内部类和公共构造函数 - 为什么它与Activator.CreateInstance一起工作
本文关键字:Activator CreateInstance 一起 工作 为什么 构造函数 内部类 | 更新日期: 2023-09-27 18:35:20
我想通过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(...)
需要公共访问(他来自包外),但为什么剩下的内部类可以做到这一点呢?
公共的时,它将与类是内部的并且构造函数也是内部的(对于分层访问层)相同......但这似乎是错误的!
有人可以帮助我理解这里发生了什么 - 为什么内部类中的公共构造函数确实有效?
指定反射的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
。
激活器使用反射来调用构造函数的正确实例。默认情况下,它可能只查找公共类成员。如 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 是一种反射类型,这里有一个关于它的堆栈溢出问题:C# 中的 System.Type 和 System.RuntimeType 有什么区别?