【问题标题】:Why is System.Activator visible as a static class in .NET Core?为什么 System.Activator 在 .NET Core 中作为静态类可见?
【发布时间】:2017-08-15 20:01:11
【问题描述】:

根据this StackOverflow question,可以使用Type.IsAbstractType.IsSealed 属性来确定一个类是否是静态的。但是,请看以下测试:

[Fact]
public void ActivatorNotAbstract()
{
    var activatorType = typeof(Activator);

    Assert.True(activatorType.IsClass);
    Assert.True(activatorType.IsSealed);
    Assert.True(activatorType.IsAbstract);
}

尽管System.Activator 被定义为静态类,但该测试失败,因为最后一个断言不正确。这对于 .NET Core 2.0(可能还有以前的版本)以及 .NET 4.5(可能还有其他版本)都是如此。你也可以在this GitHub repo找到上面的测试。

为什么Activator 在这方面很特别?我在 BCL 中找不到任何其他具有这种行为方式的静态类。

卡米洛回答后编辑

你说得对,我没有看透——在 .NET 中,该类实际上是密封的:

但是,从 .NET Core 元数据来看,它似乎是静态的:

现在,实际的问题应该是:为什么Activator 在 .NET Core 中显示为静态类(顺便说一句,在 NetStandard 中也是如此),但实际上是密封类?

【问题讨论】:

    标签: c# .net reflection .net-core


    【解决方案1】:

    这里的问题是您假设以下内容:

    虽然 System.Activator 被定义为静态类

    有趣的是,这在技术上是正确的,因为您编译所针对的库System.Activator 定义为静态类。例如,这可以在 source code of the System.Runtime reference assemblypart of the netstandard.dll reference assembly source code 中看到。

    但是,这些库是作为编译时接口的,实际的运行时实现可能会从这个声明中派生一些。

    事实上,.NET Core 和 .NET Framework 都将类实现为 public sealed class Activator (.NET Core)public sealed class Activator : _Activator (.NET Framework)

    此实现导致IsAbstract 返回false

    【讨论】:

    • 感谢您的解释,我不知道编译目标和实现类会以这种方式有所不同。
    • 是的,有几个地方,但差异仅在反映到类型时才显示出来。契约的效果是一样的——你不能从Activator继承也不能实例化它(实现中的私有构造函数)。
    【解决方案2】:

    如果你指的是System.Activator类,它根本不是静态的,look at the .NET source code

    public sealed class Activator : _Activator
    

    因此:

    • 这是一门课
    • 已密封
    • 这不是抽象的

    【讨论】:

    • 请注意,问题的一个非常重要的部分在链接的问题中:stackoverflow.com/questions/1175888/…,其中指出 type.IsAbstract && type.IsSealed 表示它是一个静态类
    • 感谢您的回答,我已经更新了我的问题。 Activator 其实是 .NET 中的一个密封类,但是从 .NET Core 元数据来看,它似乎是静态的。
    • 实际上,您可以使用 (... tada!) Activator a = Activator.CreateInstance(typeof(Activator), BindingFlags.NonPublic | BindingFlags.Instance, null, null, null); 创建Activator 的实例。你永远无法用抽象类型做到这一点。
    【解决方案3】:

    如果一个类是密封的,则意味着它不能被子类继承。如果一个类是抽象的,则意味着该类只能通过调用它的子类来使用。本质上抽象和密封是相互排斥的。

    见:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/abstract

    https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/sealed

    【讨论】:

    • 我知道抽象和密封意味着什么,请参阅更新的问题。
    • 其实static是两者的结合。在 IL 级别(C# 编译成的内容),该类被标记为 abstractsealed。对于这种组合,C# 有自己的修饰符关键字 (static),您不能组合使用 abstractsealed 修饰符。请参阅 OP 链接的问题。
    猜你喜欢
    • 1970-01-01
    • 2015-08-15
    • 1970-01-01
    • 1970-01-01
    • 2015-11-13
    • 2012-08-18
    • 2013-09-21
    • 1970-01-01
    • 2013-03-05
    相关资源
    最近更新 更多