Suppose, I have following classes:
public class DisposableObj : IDisposable
{
public ChildObj CreateObj();
internal object GetSomething();
// ...
}
public class ChildObj
{
private DisposableObj m_provider;
public void DoSomething()
{
m_provider.GetSomething();
}
// ...
}
It's possible that at some point the disposable object will be disposed but child object will still have a reference to it.
If at this time user will call DoSomething method then child object will try to access disposed object. This is not good hence the question:
How should I properly design such classes?
UPDATE/CLARIFICATION:
I am aware of ObjectDisposedException and all. My question probably should sound like: how to properly notify user about exceptional situation and how design the classes to make maintaining them easier?
While that is a scenario that is technically possible, this should be an exceptional state in your progam - I can't imagine why you would deliberately set up for this scenario.
Having said, that make it clear in your design who is responsible to dispose DisposableObj and when - if any child accesses the disposed object afterwards you can argue that this should cause an exception - don't work around this but throw an exception an let the exception bubble up so you can fix the logic when you discover the problem.
Implementation-wise you can achieve this by just keeping a boolean that keeps track of whether DisposableObj is disposed and on a later access just throw ObjectDisposedException. To clarify I mean the DisposableObj object itself should keep track of its state and throw ObjectDisposedException on any method call on it after it was disposed.
First thougth that comes to mind:
Provide your ChildObj class with an internal boolean property called ProviderDisposed.
Set this property to true from Dispose in your DisposableObj
However you should keep a list of the objects created to comunicate to each one the disposed state of your main object.
List<ChildObj> childsCreated = new List<ChildObj>();
public ChildObj CreateObj()
{
ChildObj obj = new ChildObj();
childsCreated.Add(obj);
return obj;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
if(disposing)
{
foreach(ChildObj obj in childsCreated)
obj.ProviderDisposed = true;
childsCreated = null;
}
disposed = true;
}
}
public class ChildObj
{
private DisposableObj m_provider;
private bool m_providerDisposed = false;
public bool ProviderDisposed
{ set { m_providerDisposed = true; } }
public void DoSomething()
{
if(m_providerDisposed == false)
m_provider.GetSomething();
// else // as from **#BrokenGlass answer**
// throw new ObjectDisposedException();
}
// ...
}
Related
I am coming from C++ background and would like to have some thoughts from C# (.NET) experts on the problem statement below, I am open to solution approaches but requirements are frozen.
Problem Statement:
To have a system that provides automatic cleaning of dependent objects as soon as the owning objects are deleted (bit different from what GC provides explained below.)
Dependent objects may have other references other than its owning object, but as soon as owning object is deleted the dependent objects needs to go
To be able to replace the other outstanding references with stub object (placeholder) references as the actual object no longer exit
The system needs to be object agnostic and should be able to detect references or replace them with stubs for any object inherited from System.Object (.net)
Definition of terms:
Dependent Object: An object that always needs an owner, but may be referenced by other objects as well. The Life cycle of dependent object will however be completely owned by owning object. If the owning object is deleted the dependent object must be deleted.
Stub objects These are the objects that represents the reference that got deleted.
Functional Background
To be able to support the functional requirements we need a system that will automatically clean up the dependent objects who's owner are deleted and then it would replace other references with the stub to indicate that the object it was holding has been deleted or unloaded,
To explain this with a simple example
Time T1 - Lets say we create a Line object. Since creating a line needs a start and end point it created 2 Point (Pt1 and Pt2) objects. The Point objects are marked as Dependent objects and Line Object is the Owner. So at any point of time if we delete Line it should go and delete Pt1 and Pt2.
Time T2: We create two new points Pt3 and Pt4 (these are now independent objects)
Time T3: We create a Curve object which is referencing (Pt2, Pt3 and Pt4). Here the Pt2's lifecycle is controled by Line object.
Time T4: We delete the Line object from graphics, now as a requirement this operation must go and delete Pt1 and Pt2 as they were create by Line and Line object has been deleted.
Time T5: Since curve was also referencing Pt2 hence now its geometric computation is incomplete and will be made to reference to a stub object. The Curve object will be marked as broken so that in future point of time we can edit it to refer to new point.
The key issues in having this system is that because deleting is controlled by .NET system, we do not have control over it. Any thought how this can be achieved in C# or .NET (In C++ we have complete control over memory management so it possible to determine active references from a pointer before we delete it and remove or replace them in memory).
I understand the Garbage Collector has its own tremendous benefits, but this is critical requirements which we need to support in .NET based C# model as well.
Any thought, suggestions are appreciated.
In general you can't control the deallocation of memory in C#. As suggested by Ameya, what you can do is have a "dirty" flag.
Yes I thought about the Dirty field approach, but as i have said this needs to be managed by system level. If an object is marked as Dirty other objects
Note that in .NET there are plenty of classes that do exactly this: many IDisposable classes (the ones that inherit from Stream especially!) When Dispose()d, theiy set a disposed flag to true, and in properties/methods they do a if (disposed) throw ObjectDisposedException(). In your case you shouldn't do this, you should simply return; or return (some default value);
public class ObjectWithReferences : IDisposable
{
private List<ObjectWithReferences> childs;
protected readonly ObjectWithReferences Parent;
public bool IsDisposed { get; private set; }
protected ObjectWithReferences(ObjectWithReferences parent)
{
Parent = parent;
if (parent != null)
{
parent.AddChild(this);
}
}
private void AddChild(ObjectWithReferences child)
{
if (IsDisposed)
{
child.Dispose();
return;
}
if (childs == null)
{
childs = new List<ObjectWithReferences>();
}
childs.Add(child);
}
private void DisposeChilds()
{
if (childs == null)
{
return;
}
foreach (ObjectWithReferences child in childs)
{
if (!child.IsDisposed)
{
child.Dispose();
}
}
childs = null;
}
public void Dispose()
{
if (!IsDisposed)
{
try
{
Dispose(true);
}
finally
{
try
{
DisposeChilds();
}
finally
{
IsDisposed = true;
GC.SuppressFinalize(this);
}
}
}
}
~ObjectWithReferences()
{
if (!IsDisposed)
{
try
{
Dispose(false);
}
finally
{
try
{
DisposeChilds();
}
finally
{
IsDisposed = true;
}
}
}
}
protected virtual void Dispose(bool disposing)
{
// Does nothing, not necessary to call!
}
}
Example of use:
public class ExampleRoot : ObjectWithReferences
{
public ExampleRoot() : base(null)
{
}
public void Foo()
{
if (IsDisposed)
{
return;
}
// Do Foo things
}
public void CreateChild()
{
if (IsDisposed)
{
return;
}
// Auto-adds itself!
var child = new ExampleChild(this);
}
}
public class ExampleChild : ObjectWithReferences
{
private byte[] BigBuffer = new byte[1000000];
public ExampleChild(ExampleRoot parent) : base(parent)
{
}
protected override void Dispose(bool disposing)
{
// The ExampleChild object has a very long possible lifetime,
// because it will live even in the IsDisposed == true state,
// so it is better to free even managed resources.
BigBuffer = null;
}
}
The code is quite simple/clear... There are two example classes (a Root and a Child). The basic idea is a "special" object, ObjectWithReferences that keeps the references of its childs. It is IDisposable, and when Dispose() is called (or when it is finalized) it Dispose() all its child objects. You can inherit from this object with your classes. Everyone of your methods/properties should always check the IsDisposed property to see if the object has been disposed. If it has been disposed, they should do nothing and return default values (0, null, string.Empty, ...). Note that if one of this objects keeps references to big managed objects (arrays for example), contrary to suggested .NET guidelines, it should null these references to let the GC collect them.
Note that it is the constructor that adds the object that is being built to its parent!
The normal thing to do here would be to use a WeakReference.
If you need the stub behaviour to be automatic, you could do something like:
public class AutoStubbed<T> where T:class
{
private WeakReference<T> _reference;
private T _stub;
private readonly Func<T> _stubFactory;
public AutoStubbed(T value, T stub)
{
_reference = new WeakReference<T>(value);
_stub = stub;
}
public AutoStubbed(T value, Func<T> factory)
{
_reference = new WeakReference<T>(value);
_stubFactory = factory;
}
public T Target
{
get
{
T ret;
if(_reference.TryGetTarget(out ret))
return ret;
if(_stub == null && _stubFactory != null)
_stub = _stubFactory();
return _stub;
}
}
}
And type T to a interface both your object and your stub defines, rather the type of the object.
At the moment I have the following class.
class BaseClass : IDisposable
{
private static List<BaseClass> instances = new List<BaseClass>();
protected BaseClass()
{
instances.Add(this);
}
~BaseClass()
{
Dispose();
}
public void Dispose()
{
instances.Remove(this);
}
}
So the lifetime of every class that inherit the BaseClass is infinitely until I close the program or I will call Dispose explicity.
Can I prevent this behaviour, so that lifetime is back to normal? (of course without removing the possibility to access the derived objects, otherwise my question make no sense)
I add the static List, to handle various actions to all classes that inherit BaseClass.
Edit
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();
How I can get the bahaviour that DerivedClass dc calls his destructor after the normal lifetime (as it would not be in the list)?
Background
I want to fill the Properties of the derived classes with values from a config file and do it in base class. But if the config file changed, I have to change all properties of alll derived classes. So if you know a way to get all objects that implements the base class and needs to be changed, let me know it.
Update
Solution 1: Based on my question
With help from Steve Mitcham (Go to post) I found out how I can make a weak reference with few lines of code:
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
}
}
}
Now If I call GC.Collect(); it will collect my unused derived classes (so I think the garbage collector will collect my objects normally as well) because the object itself has no reference in a list.
Thank you!
Solution 2: Subsrciber / Broadcaster Pattern
With this pattern it is simple too. Additionally the derived class can get the info if the values are changed.
Thank you Alireza (Goto post) and 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)
{
}
}
Without seeing more of your program it would be difficult to determine whether your approach could be improved. However, without fundamentally changing your design I would use WeakReferences to track your objects. The UpdateClasses method is to simulate your reconfigure action.
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);
}
}
The weak references will not keep your objects alive. When they get garbage collected they will remove their references from the instance list. Note, however, that this implementation will cause your objects to stay alive in the garbage collector longer than normal due to the requirement for the finalizer, and this may decrease the performance of the application over time.
Despite Steve Mitchman's answer, you could design a broadcaster class providing an event which gets fired whenever a change in config file is detected. Derived classes (objects) could subscribe to this event and unsubscribe upon being get GC collected or finalized. This approach follows open/closed principle very well.
When your BaseClass instance is off, that is both when you call the Dispose and when the instance itself is destroyed. These cases are normal.
In my classes I implement IDisposable as follows:
public class User : IDisposable
{
public int id { get; protected set; }
public string name { get; protected set; }
public string pass { get; protected set; }
public User(int UserID)
{
id = UserID;
}
public User(string Username, string Password)
{
name = Username;
pass = Password;
}
// Other functions go here...
public void Dispose()
{
// Clear all property values that maybe have been set
// when the class was instantiated
id = 0;
name = String.Empty;
pass = String.Empty;
}
}
In VS2012, my Code Analysis says to implement IDisposable correctly, but I'm not sure what I've done wrong here.
The exact text is as follows:
CA1063 Implement IDisposable correctly Provide an overridable implementation of Dispose(bool) on 'User' or mark the type as sealed. A call to Dispose(false) should only clean up native resources. A call to Dispose(true) should clean up both managed and native resources. stman User.cs 10
For reference: CA1063: Implement IDisposable correctly
I've read through this page, but I'm afraid I don't really understand what needs to be done here.
If anyone can explain in more layman's terms what the problem is and/or how IDisposable should be implemented, that will really help!
This would be the correct implementation, although I don't see anything you need to dispose in the code you posted. You only need to implement IDisposable when:
You have unmanaged resources
You're holding on to references of things that are themselves disposable.
Nothing in the code you posted needs to be disposed.
public class User : IDisposable
{
public int id { get; protected set; }
public string name { get; protected set; }
public string pass { get; protected set; }
public User(int userID)
{
id = userID;
}
public User(string Username, string Password)
{
name = Username;
pass = Password;
}
// Other functions go here...
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// free managed resources
}
// free native resources if there are any.
}
}
First of all, you don't need to "clean up" strings and ints - they will be taken care of automatically by the garbage collector. The only thing that needs to be cleaned up in Dispose are unmanaged resources or managed recources that implement IDisposable.
However, assuming this is just a learning exercise, the recommended way to implement IDisposable is to add a "safety catch" to ensure that any resources aren't disposed of twice:
public void Dispose()
{
Dispose(true);
// Use SupressFinalize in case a subclass
// of this type implements a finalizer.
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
// Clear all property values that maybe have been set
// when the class was instantiated
id = 0;
name = String.Empty;
pass = String.Empty;
}
// Indicate that the instance has been disposed.
_disposed = true;
}
}
The following example shows the general best practice to implement IDisposable interface. Reference
Keep in mind that you need a destructor(finalizer) only if you have unmanaged resources in your class. And if you add a destructor you should suppress Finalization in the Dispose, otherwise it will cause your objects resides in memory longer that it should (Note: Read how Finalization works). Below example elaborate all above.
public class DisposeExample
{
// A base class that implements IDisposable.
// By implementing IDisposable, you are announcing that
// instances of this type allocate scarce resources.
public class MyResource: IDisposable
{
// Pointer to an external unmanaged resource.
private IntPtr handle;
// Other managed resource this class uses.
private Component component = new Component();
// Track whether Dispose has been called.
private bool disposed = false;
// The class constructor.
public MyResource(IntPtr handle)
{
this.handle = handle;
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
protected virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
component.Dispose();
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
CloseHandle(handle);
handle = IntPtr.Zero;
// Note disposing has been done.
disposed = true;
}
}
// Use interop to call the method necessary
// to clean up the unmanaged resource.
[System.Runtime.InteropServices.DllImport("Kernel32")]
private extern static Boolean CloseHandle(IntPtr handle);
// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~MyResource()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
}
public static void Main()
{
// Insert code here to create
// and use the MyResource object.
}
}
IDisposable exists to provide a means for you to clean up unmanaged resources that won't be cleaned up automatically by the Garbage Collector.
All of the resources that you are "cleaning up" are managed resources, and as such your Dispose method is accomplishing nothing. Your class shouldn't implement IDisposable at all. The Garbage Collector will take care of all of those fields just fine on its own.
You need to use the Disposable Pattern like this:
private bool _disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
// Dispose any managed objects
// ...
}
// Now disposed of any unmanaged objects
// ...
_disposed = true;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// Destructor
~YourClassName()
{
Dispose(false);
}
You have no need to do your User class being IDisposable since the class doesn't acquire any non-managed resources (file, database connection, etc.). Usually, we mark classes as
IDisposable if they have at least one IDisposable field or/and property.
When implementing IDisposable, better put it according Microsoft typical scheme:
public class User: IDisposable {
...
protected virtual void Dispose(Boolean disposing) {
if (disposing) {
// There's no need to set zero empty values to fields
// id = 0;
// name = String.Empty;
// pass = String.Empty;
//TODO: free your true resources here (usually IDisposable fields)
}
}
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
}
Idisposable is implement whenever you want a deterministic (confirmed) garbage collection.
class Users : IDisposable
{
~Users()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
// This method will remove current object from garbage collector's queue
// and stop calling finilize method twice
}
public void Dispose(bool disposer)
{
if (disposer)
{
// dispose the managed objects
}
// dispose the unmanaged objects
}
}
When creating and using the Users class use "using" block to avoid explicitly calling dispose method:
using (Users _user = new Users())
{
// do user related work
}
end of the using block created Users object will be disposed by implicit invoke of dispose method.
I see a lot of examples of the Microsoft Dispose pattern which is really an anti-pattern. As many have pointed out the code in the question does not require IDisposable at all. But if you where going to implement it please don't use the Microsoft pattern. Better answer would be following the suggestions in this article:
https://www.codeproject.com/Articles/29534/IDisposable-What-Your-Mother-Never-Told-You-About
The only other thing that would likely be helpful is suppressing that code analysis warning... https://learn.microsoft.com/en-us/visualstudio/code-quality/in-source-suppression-overview?view=vs-2017
I was recently going through a garbage collection article and decided to play along and attempt to gain a greater understanding. I coded the following, playing around with the using statement, but was surprised with the results... I expected e.Parent.Name outside of the using block to go ka-blooey.
What exactly is going on here?
static void Main(string[] args)
{
Employee e = new Employee();
using (Parent p = new Parent())
{
p.Name = "Betsy";
e.Parent = p;
Console.WriteLine(e.Parent.Name);
}
Console.WriteLine(e.Parent.Name);
Console.ReadLine();
}
public class Employee
{
public Parent Parent;
}
public class Parent : IDisposable
{
public string Name;
public void Dispose()
{
Console.WriteLine("Disposing Parent");
}
}
Your Dispose method doesn't actually do anything to the instance of Parent, hence it's still fair game / works as a usable instance of a class.
IDisposable is usually used when your class holds onto an unmanaged resource, such as a database connection or a file, so that it can be cleaned up when Dispose() is called. Just calling Dispose doesn't do anything to the unmanaged resources, there has to be some code in the method that does something to those resources. Whilst c# might have the using() {} syntax to wrap instantiation and disposal of an IDisposable object in a try/catch/finally, it doesn't mean it does anything "special" with the disposed object.
Imagine, hypothetically, that Name is actually an unmanaged resource, rather than just a string, your Dispose() method could read:
public void Dispose()
{
Name = null;
Console.WriteLine("Disposing Parent");
}
Because you've assigned p to e.Parent, the object itself is still "in scope" as there's a reference to it, hence it's still accessible for Console.WriteLine(e.Parent.Name); to produce output from.
It's also currently "CLR Week" over at The Old New Thing and the first 3 articles of the week are discussing the Garbage Collector and how it works/behaves. They're well worth a read:
Everybody thinks about garbage collection the wrong way
When does an object become available for garbage collection?
Everybody thinks about CLR objects the wrong way (well not everybody)
IDisposable.Dispose is intended for you to use it to clean up unmanaged resources that you own (like file handles etc.) It doesn't do anything in its own right. The most common usage is if your class had member variables that implement IDisposable themselves, you now have responsibility for Dispose'ing them. It's just a pattern to help you, and has nothing to do with Garbage Collection - quite the opposite in fact.
The Dispose method does not destroy the object from memory. Normally a dispose method will only free up resources that it created.
Since e still exists in scope that anything associated with e (the parent assigned to e) will still exist until e is out of scope.
IDisposable is not a language feature, and does nothing special in the runtime. It is just an interface/method like any other. It happens to be a useful pattern, so they added syntax to automatically call that method in a specific pattern (using), and there are special exceptions you can throw that have "Dispose" in their name (like ObjectDisposedException).
using blocks turn from this:
using(SomeType t = new SomeType())
{
t.Something();
}
into something like this:
{
SomeType t;
try
{
t = new SomeType();
t.Something();
}
finally
{
t.Dispose();
}
}
There is absolutely no way to force the GC to collect anything. If there are references to your object somewhere in the stack (ignoring unsafe and C++/CLI code), or chained references to it from some object on the stack, then your object will live.
If you want that code to blow up, you can do something like this:
public class Parent : IDisposable
{
public string Name
{
get
{
AssertNotDisposed();
return name;
}
set
{
AssertNotDisposed();
name = value;
}
}
public void Dispose()
{
AssertNotDisposed();
Console.WriteLine("Disposing Parent");
isDisposed = true;
}
private void AssertNotDisposed()
{
if(isDisposed)
throw new ObjectDisposedException("some message");
}
private string name;
private bool isDisposed = false;
}
If you're looking for another example that will blow up when trying to do something to a disposed object.
static void Main(string[] args)
{
Employee e = new Employee();
using (Parent p = new Parent("test.txt"))
{
e.Parent = p;
using ( System.IO.StreamWriter fileWriter =
new System.IO.StreamWriter(e.Parent.File))
{
fileWriter.WriteLine("Betsy");
}
}
using (System.IO.StreamWriter fileWriter =
new System.IO.StreamWriter(e.Parent.File))
{
fileWriter.WriteLine("Betsy"); //uh-oh
}
Console.ReadLine();
}
public class Employee
{
public Parent Parent;
}
public class Parent : IDisposable
{
public System.IO.FileStream File;
public Parent(string fileName)
{
File = System.IO.File.Open(fileName, System.IO.FileMode.OpenOrCreate);
}
public void Dispose()
{
((IDisposable)File).Dispose(); //or File.Close();
}
}
So I'm working on my DI/IoC Container OpenNETCF.IoC and I've got a (reasonable) feature request to add some form of lifecycle management for IDisposable items in the container collections.
My current thinking is that, since I can't query an object to see if it's been disposed, and I can't get an event for when it's been disposed, that I have to create some form of wrapper for objects that a developer wants the framework to manage.
Right now objects can be added with AddNew (for simplicity sake we'll assume there's only one overload and there is no Add):
public TTypeToBuild AddNew<TTypeToBuild>() { ... }
What I'm considering is adding a new method (well group of them, but you get the picture):
public DisposableWrappedObject<IDisposable> AddNewDisposable<TTypeToBuild>()
where TTypeToBuild : class, IDisposable
{
...
}
Where the DisposableWrappedObject looks like this:
public class DisposableWrappedObject<T>
where T : class, IDisposable
{
public bool Disposed { get; private set; }
public T Instance { get; private set; }
internal event EventHandler<GenericEventArgs<IDisposable>> Disposing;
internal DisposableWrappedObject(T disposableObject)
{
if (disposableObject == null) throw new ArgumentNullException();
Instance = disposableObject;
}
~DisposableWrappedObject()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
lock(this)
{
if(Disposed) return;
EventHandler<GenericEventArgs<IDisposable>> handler = Disposing;
if(handler != null)
{
Disposing(this, new GenericEventArgs<IDisposable>(Instance));
}
Instance.Dispose();
Disposed = true;
}
}
}
Now, when an items gets added to the container via AddNewDIsposable, an eventhandler is also added so that when it gets Disposed (via the wrapper) the framework removes it from the underlying collection.
I actually have this implemented and it's passing the unit tests, but I'm looking for opinions on where this might be broken, or how it might be made more "friendly" to the consuming developer.
EDIT 1
Since there was a question on how the Disposing event is used, here's some code (trimmed to what's important):
private object AddNew(Type typeToBuild, string id, bool wrapDisposables)
{
....
object instance = ObjectFactory.CreateObject(typeToBuild, m_root);
if ((wrapDisposables) && (instance is IDisposable))
{
DisposableWrappedObject<IDisposable> dispInstance = new
DisposableWrappedObject<IDisposable>(instance as IDisposable);
dispInstance.Disposing += new
EventHandler<GenericEventArgs<IDisposable>>(DisposableItemHandler);
Add(dispInstance as TItem, id, expectNullId);
instance = dispInstance;
}
....
return instance;
}
private void DisposableItemHandler(object sender, GenericEventArgs<IDisposable> e)
{
var key = m_items.FirstOrDefault(i => i.Value == sender).Key;
if(key == null) return;
m_items.Remove(key);
}
Maybe I'm missing something, but why add new methods to the API? When an object is added to the container, you could as-cast to check if it's IDisposable and handle it appropriately if so.
I'm also wondering if you need the destructor. Presuming the container is IDisposable (like Unity's), you could just implement the Basic Dispose Pattern and save a lot of GC overhead.
Some questions that may be applicable:
How do you reconcile IDisposable and IoC?
Can inversion of control and RAII play together?