通过本地静态实例访问实例成员

时间:2017-08-09 07:44:42

标签: c# static instance

我有一个通过反序列化实例化的通信管理器。 现在我想创建一些静态方法来访问实例数据。

在其他帖子上,我看到人们建议不要访问实例对象的静态字段。但是现在我创建了以下代码,这个工作就像预期的一样,我可以反序列化并使用静态方法而无需新的CommManager实例。大!

问题: 这是方法安全吗? 我想应用Threading,GetChannel是我的应用程序的核心,并将被多个线程上的许多应用程序部分使用。我觉得重要的是我不会造成性能损失或其他后果。请指教。

我问这个原因我发现奇怪的是我找不到这种方法的任何类似例子,我现在看到它的方式,我可以很容易地使每个方法都是静态的而没有缺点。

public class CommManager
{
    public ObservableCollection<ChannelConfig> channelConfigs;        
    private List<iChannel> channels;        
    private static CommManager StaticMe;

    public CommManager()
    {
        channelConfigs.CollectionChanged += ChannelCollectionChanged;
        StaticMe = this;            
    }

    private void ChannelCollectionChanged(object sender, 
        NotifyCollectionChangedEventArgs args)
    {
        if (channels == null)
            channels = new List<iChannel>();
        switch (args.Action)
        {
            case NotifyCollectionChangedAction.Add:
                foreach (ChannelConfig newItem in args.NewItems)
                    channels.Add(CreateChannel(newItem));
                break;
            case Notif.. /// etc. etc.
        }
    }

    /// <summary>
    /// I can access this method without instance and i get normal de-serialized values
    /// </summary>
    public static iChannel GetChannel(CommChannel channelnr)
    {
         return StaticMe.Channels[(int)channelnr];
    }
}

1 个答案:

答案 0 :(得分:0)

当您创建类的第二个实例时,可能会出现问题。

静态字段只能存在一次。覆盖静态字段的那一刻,它将更改对新对象的引用。

设置为旧对象的任何旧引用仍可能在其他地方使用更新 - 或者更糟糕的是,如果它包含任何数据,则可能会意外更改。

CommManager manager = new CommManager();
manager.GetChannel(); 
// refers to the static field StaticMe.channels which is manager.channels.

CommManager manager2 = new CommManager();
manager2.GetChannel();
// refers to the static field StaticMe.channels which is manager2.channels.
manager.GetChannel();
// still exists, now refers to manager2.channels because of StaticMe now being manager2
// It is not retaining any of the original channels because of the changed reference.

因此,静态字段或属性最好是不可变的,不依赖于静态属性中存储的除默认值或固定值之外的任何内容。

如果您确实需要全局存储可变值,请不要在构造函数或任何实例方法中分配它们,而是在定义上分配它们。

如果您的频道应该全局可用,那么通过将该频道设为静态只读来使全局可用(因为列表引用将保持不变,只有内容可能会更改)。

// for brevity, removed all unchanged parts...
public class CommManager
{
    private static readonly List<IChannel> channels = new List<IChannel>();

    private void ChannelCollectionChanged(object sender, 
        NotifyCollectionChangedEventArgs args)
    {
        switch (args.Action)
        {
            case NotifyCollectionChangedAction.Add:
                foreach (ChannelConfig newItem in args.NewItems)
                    CommManager.channels.Add(CreateChannel(newItem));
                break;
            case Notif.. /// etc. etc.
        }
    }

    public static IChannel GetChannel(CommChannel channelNr)
    {
        return CommManager.channels[(int)channelNr];
    }
}

此外,如果您要采用多线程方法,则可能需要一个线程安全的ConcurrentBag<T>而不是正常的List<T>,而不是。{/ p>