我有一个通过反序列化实例化的通信管理器。 现在我想创建一些静态方法来访问实例数据。
在其他帖子上,我看到人们建议不要访问实例对象的静态字段。但是现在我创建了以下代码,这个工作就像预期的一样,我可以反序列化并使用静态方法而无需新的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];
}
}
答案 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>