【问题标题】:Static Objects Are Null/Not Initialized At Correct time静态对象为空/未在正确时间初始化
【发布时间】:2015-08-12 17:32:09
【问题描述】:

我正在使用此处列出的type-safe enum pattern。我需要将一个类型安全的枚举嵌套到另一个中。在创建父构造函数时,子属性(静态对象)为 NULL。似乎没有调用子构造函数并且我遇到了一些错误。(父子关系我很困惑,但它解释了层次结构)

这是一个例子(我使用的是 netMF):

public class MyDeviceSetting //parent
{
        public readonly string Name;
        public MyUnit SettingUnit;
        public readonly MyUnit.UnitPurpose UnitPurpose;

          #region MY STATIC SETTINGS
        //UNIT SETTINGS
        public static MyDeviceSetting TempUnits = new MyDeviceSetting("TempUnits", MyUnit.mm); //MyUnit.mm is null. Why?
        public static MyDeviceSetting BLAH = new MyDeviceSetting("BLAH", MyUnit.inch);//MyUnit.inch is null. Why?
          #endregion



        /// <summary>
        /// This is the MAIN PRIVATE Constructor
        /// </summary>
        /// <param name="?"></param>
        private MyDeviceSetting(string name, MyUnit defaultUnit)
        {
            Name = name;
            SettingUnit = defaultUnit;//NULL
            UnitPurpose = SettingUnit.Purpose; //fails because SettingUnit is NULL


        }


    }


public sealed class MyUnit
{
    private static int Count = 0;

    //these are used to store and identify the unit in memory
    public readonly int UnitID;
    public readonly int TestID;

    public enum UnitPurpose
    {
        DISTANCE,
        SPEED,
        TEMPERATURE,
        TIME,
        CLOCK,
        NO_UNITS
    }

    public readonly string DisplayName;
    public readonly string Abbreviation;
    public readonly string Name;
    public readonly UnitPurpose Purpose;

    #region My Units
    public static readonly MyUnit mm = new MyUnit("Milimeters", "mm", "mm", UnitPurpose.DISTANCE, 1);
    public static readonly MyUnit inch = new MyUnit("inch", "inch", "in", UnitPurpose.DISTANCE, 2);



    #endregion

    private MyUnit(string name,
                   string displayName,
                   string abbreviation,
                   UnitPurpose unitPurpose,
                   int unitID)
    {
        Name = name;
        DisplayName = displayName;
        Abbreviation = abbreviation;
        Purpose = unitPurpose;
        UnitID = unitID;
        TestID = Count;
        Count++;

    }


}

如何确保child 不为空?有解决办法吗?编辑:This Post 确保这应该可以正常工作,但在我的情况下它不起作用。

【问题讨论】:

  • 您提供的代码无法编译,但在进行了编译所需的琐碎更改后,它可以正常工作。请提供一个简短但完整的示例来实际演示该问题。
  • @JuanK 成为Enum的目的
  • @GusMofx 我已经测试过您是上次更新的代码,但一切看起来都不错,您告诉我们的代码必须失败或导致 null... 工作正常。 :S
  • @GisMofx 有人将 null 传递给构造函数。我不知道为什么,因为您没有向我们展示该代码。
  • 在这种情况下,这听起来可能是 netMF 的错误。您应该在问题中提及并为其添加标签。

标签: c# .net enums static .net-micro-framework


【解决方案1】:

这似乎是 .Net Micro 框架的错误/限制。它不完全支持静态构造函数。有人报告了同样的问题:https://msdn.microsoft.com/en-us/library/Cc533032.aspx

NetCF 3.0 的 documentation 包含以下警告:

不要使用静态构造函数。 .NET Micro Framework 尚未完全支持它们。

从这个blog post 看来,对静态构造函数的调用(至少从 2.0 开始)是序列化的:

有些事情在 .NET Compact Framework 中是无法做到的 在完整的 .NET Framework 中可以使用的静态构造函数。 基本上,所有静态构造函数都在序列化中执行 .NET Compact Framework V2 中的时尚

那篇文章在死锁的背景下讨论了它,但我相信这是它不起作用的原因。

不幸的是,这意味着您不能依赖静态数据,而必须自己处理初始化和锁定。像这样的东西应该可以工作:

private static MyUnit inch;

public static MyUnit Inch
{
    get
    {
        if (inch == null)
            inch = new MyUnit("inch", "inch", "in", UnitPurpose.DISTANCE, 2);
         return inch;
    }
}

不幸的是,这失去了静态构造函数为您提供的线程安全性。这将很难解决,因为您不能依赖静态成员,因为正如我们所见,您不能依赖它们被初始化。

【讨论】:

  • 对静态构造函数的调用已序列化: 很有趣。我受到启发将MyUnit 重命名为MyAUnit,并且初始化似乎是按字母顺序/字母数字顺序/随便排序的。现在它之前调用了那些构造函数,我不再得到 NULL 运行时错误!
【解决方案2】:

作为一种解决方法,您可以将 MyUnit 类移动到另一个名为 MyUnit.cs 的源文件中,这将导致 .netmf CLR 首先加载此类。

我已经在运行 .Netmf 4.3 RTM 的环境中进行了测试。

【讨论】:

    【解决方案3】:

    除了@shf301 以及它无法正常工作的原因之外,似乎构造函数在编译时以某种字母/字母数字顺序调用。

    将子类重命名为MyAUnit使其位于MyDeviceSetting 之前,并且似乎在MyDeviceSettingstatic 成员之前触发MyAUnit 静态成员。

    这似乎可行,但暂时有点“破解”。

    【讨论】:

      【解决方案4】:

      看起来你的问题很难复制,无论如何都需要务实。

      您可以让MyUnit 静态字段在MyDeviceSetting 静态字段之前初始化,只需调用MyUnit

      这很简单,只需在程序中的任何其他内容之前创建一个虚拟变量即可。

      public class MyDeviceSetting //parent
      {
          static MyDeviceSetting()
          {
              var dummy = MyUnit.inch;
          }
      }
      

      因此,从不使用 dummy var,但会初始化 MyUnit 的静态实例。

      之后,任何带有MyDeviceSetting 的活动都将初始化MyUnit

      【讨论】:

      • 我试过了。它仍然在 Parent 类之后初始化。
      • 这不应该发生。你在哪里创建虚拟变量?只需在程序启动后执行的第一行代码中执行此操作即可。
      • @GisMofx 我已经修改了将虚拟变量放入 MyDeviceSetting 新静态构造函数的代码。静态构造函数 + 虚拟初始化应该可以工作。
      • 你可以试试netMF吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-11
      • 1970-01-01
      • 2021-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多