静态属性是被分配后空

静态属性是被分配后空

本文介绍了静态属性是被分配后空的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这样的代码:

 静态类全球
{
公共静态只读IChannelsData通道=新ChannelsData();
公共静态只读IMessagesData消息=新MessagesData();
}



我的理解是,因为这个类是静态的,它是不可能 Global.Channels Global.Messages 现在他们被赋予一个实例为空。



不过,我尝试用

 公共类信道访问属性:IComparable的
{



私人排序列表<字符串,消息> _messages;

[JsonConstructor]
公共频道()
{
_messages =新SortedList的<字符串,消息>();
}

[OnDeserialized]
私人无效初始化(的StreamingContext上下文)
{
** Global.Channels.RegisterChannel(本); **
}



}

我收到了的NullReferenceException Global.Channels ,这是我在即时窗口中确认。另外困惑我,我可以在命中断点新ChannelData(),所以我知道的静态成员被填充 - 成功 - 在某些点



更多的情况下,要求注释:

 私人Hashtable的_channels; 

公共ChannelsData()
{
_channels =新的Hashtable();

的foreach(在SlackApi.ChannelList通道通道())
{
_channels.Add(channel.GetHashCode(),信道);
}
}



这感觉就像类似问题的。然而,在我的情况我使用JSON.NET而不是WCF的和反序列化的有关财产是在一个单独的静态类,而不是在同一个班级。我也不能使用贴有一个解决方案的解决方法。



完整堆栈跟踪:



And error:

解决方案

I've been able to reproduce it with the following:

class Program
{
    static void Main(string[] args)
    {
        var m = Global.Messages;
    }
}
[Serializable]
public class Blah
{
    [OnDeserialized]
    public void DoSomething(StreamingContext context)
    {
        Global.Channels.DoIt(this);
    }
}
static class Global
{
    private static Blah _b = Deserialize();

    public static readonly IChannelsData Channels = new ChannelsData();
    public static readonly IMessagesData Messages = new MessagesData();

    public static Blah Deserialize()
    {
        var b = new Blah();
        b.DoSomething(default(StreamingContext));
        return b;
    }
}

Essentially, the order of execution is:

var m = Global.Messages; causes the static initializer to run for Global.

According to ECMA-334 regarding static field initialization:

This is the root cause. See the comments for more context on the circular reference

This essentially means that we're calling Deserialize and hitting Global.Channels.DoIt(this); before the initializer has a chance to finish setting up. As far as I'm aware, this is the only way a static field cannot be initialized before being used - after some testing, they are indeed created even when using run-time dispatches (dynamic), reflection and GetUninitializedObject (for the latter, initialization is done on the first method call, however)..

Though your code may be less obvious to diagnose (for example, if the chain is kicked off by another static class referencing). For example, this will cause the same issue but is not as immediately clear:

class Program
{
   static void Main(string[] args)
   {
       var t = Global.Channels;
   }
}
[Serializable]
public class Blah
{
   [OnDeserialized]
   public void DoSomething(StreamingContext context)
   {
       Global.Channels.DoIt();
   }
}

public interface IChannelsData { void DoIt(); }
class ChannelsData : IChannelsData
{
    public static Blah _b = Deserialize();
    public static Blah Deserialize()
    {
        var b = new Blah();
        b.DoSomething(default(StreamingContext));
        return b;
    }
    public void DoIt()
    {
        Console.WriteLine("Done it");
    }
}

static class Global
{
    public static readonly IChannelsData Channels = new ChannelsData();
    public static readonly IMessagesData Messages = new MessagesData();
}

So:

  1. If you have anything else in Globals before those fields, you should investigate them (if they were left out for brevity). It may be simple as moving the Channels declaration to the top of the class.
  2. Inspect ChannelsData for any static references, and follow those to the source.
  3. Setting a breakpoint in DoSomething should give you a stack trace back to the static initializers. If it doesn't, try to replicate the issue by invoking new Blah(default(StreamingContext)) where it would usually be deserialised.

这篇关于静态属性是被分配后空的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-14 15:32