静态对象在正确的时间是空的/未初始化

时间:2015-08-12 17:32:09

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

我正在使用此处列出的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确保此功能正常运行,但就我而言,它无效。 Null

4 个答案:

答案 0 :(得分: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;
    }
}

遗憾的是,它失去了静态构造函数给你的线程安全性。这很难解决,因为你不能依赖静态成员,因为我们已经看到你不能依赖它们被初始化。

答案 1 :(得分:1)

作为一种解决方法,您可以将offset = rand(Quote.count) rand_record = Quote.offset(offset).first 类移动到另一个名为MyUnit.cs的源文件,这将导致.netmf CLR首先加载此类。

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

答案 2 :(得分:0)

看起来你的问题很难复制,任何方式都需要务实。

您可以在MyUnit静态字段首先调用MyDeviceSetting之前初始化MyUnit个静态字段。

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

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

因此,永远不会使用虚拟var,但会初始化MyUnit的静态实例。

之后,MyDeviceSetting的所有活动都会初始化MyUnit

答案 3 :(得分:0)

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

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

这似乎有效,但暂时还有点“黑客”。