简单回顾一下 Dispose
处理一些非托管资源的时候需要用。
其实也可以借助这个,来实现 RAII
。
using (var obj = new Base()) {
}
using (var obj = new Derived()) {
}
using (Base obj = new Derived()) {
}
class Base : IDisposable
{
// 标记该对象是否已被释放
private bool _disposed = false;
~Base() => Dispose(false);
// Dispose 接口
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// 非密封类最好使用这样的模式
protected virtual void Dispose(bool disposing)
{
if (!_disposed) {
// 清理非托管资源
if (disposing) {
Console.WriteLine("Base disposing.");
}
_disposed = true;
}
}
}
sealed class Derived : Base
{
private bool _disposed = false;
~Derived() => Dispose(false);
protected override void Dispose(bool disposing) {
// 注意这里的范围
if (!_disposed) {
if (disposing) {
Console.WriteLine("Derived disposing.");
}
_disposed = true;
}
// 调用基类 Dispose 方法
base.Dispose(disposing);
}
}
当使用 using
方式时,可以在对象超过作用域后自动调用 Dispose
方法。有什么用?如果你的对象中涉及到一些必须要回收资源等等的情况下,这是最好的处理方式,而不是 try finally
。
using var @base = new Base();
// 如果可以的话,最好不要
var @base = new Base();
try {
} catch (Exception e) {
} finally {
@base.Dispose();
}
一个具体的使用场景就像下面一样。
using System.Buffers;
using System.Collections;
using System.Runtime.CompilerServices;
using Dumpify;
using PooledArray<int> arr = [1, 2, 3];
arr.Dump();
[CollectionBuilder(typeof(PooledArrayBuilder), "Create")]
public class PooledArray<T> : IDisposable, IEnumerable<T>
{
private bool _disposed = false;
private readonly T[] _array;
private readonly int _length;
/// <summary>
/// 分配时的数组长度
/// </summary>
public int Length => _length;
public PooledArray(int length)
{
_length = length;
_array = ArrayPool<T>.Shared.Rent(length);
}
public PooledArray(ReadOnlySpan<T> span)
{
_length = span.Length;
_array = ArrayPool<T>.Shared.Rent(_length);
span.CopyTo(_array);
}
public PooledArray(T[] array) : this(array.AsSpan())
{
}
~PooledArray() => Dispose(false);
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
try
{
ArrayPool<T>.Shared.Return(_array);
}
catch (Exception)
{
// Ignore
}
}
_disposed = true;
}
}
private void ThrowIfDisposed()
{
if (_disposed)
throw new ObjectDisposedException(nameof(PooledArray<T>));
}
public Span<T> AsSpan()
{
ThrowIfDisposed();
return _array.AsSpan(0, _length);
}
public Span<T> Span => AsSpan();
public Memory<T> AsMemory()
{
ThrowIfDisposed();
return _array.AsMemory(0, _length);
}
public Memory<T> Memory => AsMemory();
public ArraySegment<T> AsArraySegment()
{
ThrowIfDisposed();
return new ArraySegment<T>(_array, 0, _length);
}
public ArraySegment<T> ArraySegment => AsArraySegment();
public T this[Index i]
{
get
{
ThrowIfDisposed();
var index = i.GetOffset(_length);
if (index < 0 || index >= _length)
throw new IndexOutOfRangeException();
return _array[index];
}
set
{
ThrowIfDisposed();
var index = i.GetOffset(_length);
if (index < 0 || index >= _length)
throw new IndexOutOfRangeException();
_array[index] = value;
}
}
public IEnumerator<T> GetEnumerator()
{
for (int i = 0; i < _length; i++)
yield return _array[i];
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public static class PooledArrayBuilder
{
/// <summary>
/// 为 PooledArray 类型提供集合表达式初始化的方式。
/// </summary>
/// <param name="span"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static PooledArray<T> Create<T>(ReadOnlySpan<T> span) => new(span);
}
public static class PooledArrayExtensions
{
public static PooledArray<T> ToBlockArray<T>(this T[] self) => new PooledArray<T>(self);
public static T[] ToArray<T>(this PooledArray<T> self) => self.Span.ToArray();
}