I received some feedback on yesterday's post, pointing out that it was hard to get the whole story of Disposal<T>'s implementation. Here's the full listing:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
namespace DisposalMonad
{
public static class Disposal
{
public static Disposal<T> Unit<T>(T value) where T : class, IDisposable
{
return new Disposal<T>(value, Enumerable.Repeat(value, 1));
}
}
public class Disposal<T> : IDisposable
{
private readonly T _Value;
private readonly IEnumerable<IDisposable> _Disposables;
internal Disposal(T value, IEnumerable<IDisposable> disposables)
{
_Value = value;
_Disposables = new ReadOnlyCollection<IDisposable>(disposables.ToList());
}
public T Value
{
get { return _Value; }
}
public IEnumerable<IDisposable> Disposables
{
get { return _Disposables; }
}
public Disposal<U> Select<U>(Func<T, U> selector)
{
var result = selector(this.Value);
return new Disposal<U>(result, this.Disposables);
}
public Disposal<V> SelectMany<U, V>(Func<T, Disposal<U>> intermediateSelector,
Func<T, U, V> resultSelector)
{
var intermediateDisposal = intermediateSelector(this.Value);
var result = resultSelector(this.Value, intermediateDisposal.Value);
var disposables = Enumerable.Concat(intermediateDisposal.Disposables, this.Disposables);
return new Disposal<V>(result, disposables);
}
public void Dispose()
{
foreach (var disposable in this.Disposables)
{
disposable.Dispose();
}
}
}
}
An interesting side point is that Disposal<T> can be turned into something a bit like a linear type - just remove both of the public properties and replace them with the following methods:
public void UseWith(Action<T> action)
{
using (this)
{
action(_Value);
}
}
public U UseIn<U>(Func<T, U> selector)
{
using (this)
{
return selector(_Value);
}
}
This might be overkill, though. It makes the class much harder to use and I'm not sure it adds much that will be useful to most applications.
No comments:
Post a Comment