目前,我有以下课程。
class BaseClass : IDisposable
{
private static List<BaseClass> instances = new List<BaseClass>();
protected BaseClass()
{
instances.Add(this);
}
~BaseClass()
{
Dispose();
}
public void Dispose()
{
instances.Remove(this);
}
}
因此,在我关闭程序之前,继承BaseClass
的每个类的生命周期都是无限的,否则我将调用Dispose explicity。
我可以阻止此行为,以便终身恢复正常吗? (当然没有删除访问派生对象的可能性,否则我的问题毫无意义)
我添加静态List,以处理继承BaseClass
的所有类的各种操作。
class DerivedClass : BaseClass
{
}
//This case works
using (DerivedClass _dc = new DerivedClass())
{
//Do something with object
}
//This object will live forever, because it is internally in the static list
//That behaviour is not desired
DerivedClass dc = new DerivedClass();
我怎样才能得到DerivedClass dc
在正常生命之后调用他的析构函数的行为(因为它不在列表中)?
我想用配置文件中的值填充派生类的属性,并在基类中执行。但是如果配置文件发生了变化,我必须更改alll派生类的所有属性。因此,如果您知道获取实现基类并需要更改的所有对象的方法,请告诉我。
在Steve Mitcham(Go to post)的帮助下,我发现了如何使用几行代码制作弱引用:
class BaseClass : IDisposable
{
private static List<GCHandle> handles = new List<GCHandle>();
protected BaseClass()
{
this.handle = GCHandle.Alloc(this, GCHandleType.Weak);
handles.Add(this.handle);
}
~BaseClass()
{
Dispose();
}
public void Dispose()
{
if (handle.IsAllocated)
{
//Do Something more to Dispose the Object
//...
handle.Free();
handles.Remove(handle);
}
}
public void DoSomethingWithTheList()
{
foreach (GCHandle handle in handles)
{
BaseClass bc = (BaseClass)handle.Target;
//Do something
}
}
}
现在如果我调用GC.Collect();
它将收集我未使用的派生类(所以我认为垃圾收集器也会正常收集我的对象)因为对象本身在列表中没有引用。
谢谢!
使用这种模式也很简单。此外,如果值已更改,派生类可以获取信息。 感谢您Alireza(Goto post)和Thangadurai。
class ConfigurationBroadcaster
{
string path = "";
public string Path
{
get { return path; }
set
{
bool changed = path != value;
path = value;
if(changed)
if (ChangedConfigurationValues != null)
{
Delegate[] invocationList = ChangedConfigurationValues.GetInvocationList();
foreach (var item in invocationList)
{
Type t = item.Target.GetType();
PropertyInfo[] pInfos = t.GetProperties();
foreach (PropertyInfo pInfo in pInfos)
{
//new object() have to be the value from config file
//5 is used to set Width and Height from BroadcastSubscriber for this example
pInfo.SetValue(item.Target, 5/* new object()*/, null);
}
}
ChangedConfigurationValues(this, new EventArgs());
}
}
}
public event EventHandler ChangedConfigurationValues;
}
class BaseBroadcastSubscriber
{
ConfigurationBroadcaster broadcaster;
protected BaseBroadcastSubscriber(ConfigurationBroadcaster broadcaster)
{
this.broadcaster = broadcaster;
this.broadcaster.ChangedConfigurationValues += new EventHandler(broadcaster_ChangedConfigurationValues);
}
void broadcaster_ChangedConfigurationValues(object sender, EventArgs e)
{
Console.WriteLine("Configuration values changed");
}
}
class BroadcastSubscriber : BaseBroadcastSubscriber
{
int width,height;
public int Width
{
get { return width; }
set { width = value; }
}
public int Height
{
get { return height; }
set { height = value; }
}
public BroadcastSubscriber(ConfigurationBroadcaster broadcaster)
: base(broadcaster)
{
}
}
答案 0 :(得分:4)
如果没有看到更多的程序,就很难确定您的方法是否可以改进。但是,如果不从根本上改变您的设计,我会使用WeakReferences来跟踪您的对象。 UpdateClasses方法用于模拟重新配置操作。
class BaseClass : IDisposable
{
private WeakReference<BaseClass> myReference;
private static List<WeakReference<BaseClass>> instances = new List<WeakReference>();
public static UpdateClasses(MyData stuff)
{
foreach(var ref in instances)
{
BaseClass target;
if (ref.TryGetTarget(out target))
{
// code to update target here
}
}
}
protected BaseClass()
{
myReference = new WeakReference<BaseClass>(this,true);
instances.Add(myReference);
}
~BaseClass()
{
Dispose();
}
public void Dispose()
{
instances.Remove(myReference);
}
}
弱引用不会让你的对象保持活着。当他们收集垃圾时,他们将从实例列表中删除他们的引用。但请注意,由于需要终结器,此实现将导致您的对象在垃圾收集器中保持活动时间超过正常值,这可能会降低应用程序的性能。
答案 1 :(得分:1)
尽管史蒂夫·米奇曼的答案,你可以设计一个广播者类,提供一个事件,只要检测到配置文件发生变化就会被触发。派生类(对象)可以订阅此事件,并在获取或最终确定GC时取消订阅。这种方法很好地遵循开放/封闭原则。
答案 2 :(得分:0)
当您的BaseClass实例关闭时,既可以调用Dispose,也可以在实例本身被销毁时使用。这些情况很正常。