Skip to content

Commit a6f4f8e

Browse files
Merge pull request #1009 from SixLabors/feature/idisposable
Refactor IDisposable pattern
2 parents 644fe22 + b0ef8a1 commit a6f4f8e

File tree

8 files changed

+63
-52
lines changed

8 files changed

+63
-52
lines changed

src/ImageSharp/IImage.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) Six Labors and contributors.
1+
// Copyright (c) Six Labors and contributors.
22
// Licensed under the Apache License, Version 2.0.
33

44
using System;
@@ -11,4 +11,4 @@ namespace SixLabors.ImageSharp
1111
public interface IImage : IImageInfo, IDisposable
1212
{
1313
}
14-
}
14+
}

src/ImageSharp/Image.cs

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Six Labors and contributors.
22
// Licensed under the Apache License, Version 2.0.
33

4+
using System;
45
using System.IO;
56

67
using SixLabors.ImageSharp.Advanced;
@@ -80,21 +81,11 @@ internal Image(
8081
/// </summary>
8182
Configuration IConfigurable.Configuration => this.Configuration;
8283

83-
/// <summary>
84-
/// Gets a value indicating whether the image instance is disposed.
85-
/// </summary>
86-
public bool IsDisposed { get; private set; }
87-
8884
/// <inheritdoc />
8985
public void Dispose()
9086
{
91-
if (this.IsDisposed)
92-
{
93-
return;
94-
}
95-
96-
this.IsDisposed = true;
97-
this.DisposeImpl();
87+
this.Dispose(true);
88+
GC.SuppressFinalize(this);
9889
}
9990

10091
/// <summary>
@@ -109,7 +100,7 @@ public void Save(Stream stream, IImageEncoder encoder)
109100
Guard.NotNull(encoder, nameof(encoder));
110101
this.EnsureNotDisposed();
111102

112-
EncodeVisitor visitor = new EncodeVisitor(encoder, stream);
103+
var visitor = new EncodeVisitor(encoder, stream);
113104
this.AcceptVisitor(visitor);
114105
}
115106

@@ -144,9 +135,15 @@ public abstract Image<TPixel2> CloneAs<TPixel2>(Configuration configuration)
144135
protected void UpdateSize(Size size) => this.size = size;
145136

146137
/// <summary>
147-
/// Implements the Dispose logic.
138+
/// Disposes the object and frees resources for the Garbage Collector.
139+
/// </summary>
140+
/// <param name="disposing">Whether to dispose of managed and unmanaged objects.</param>
141+
protected abstract void Dispose(bool disposing);
142+
143+
/// <summary>
144+
/// Throws <see cref="ObjectDisposedException"/> if the image is disposed.
148145
/// </summary>
149-
protected abstract void DisposeImpl();
146+
internal abstract void EnsureNotDisposed();
150147

151148
private class EncodeVisitor : IImageVisitor
152149
{

src/ImageSharp/ImageExtensions.cs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) Six Labors and contributors.
1+
// Copyright (c) Six Labors and contributors.
22
// Licensed under the Apache License, Version 2.0.
33

44
using System;
@@ -119,16 +119,5 @@ public static string ToBase64String<TPixel>(this Image<TPixel> source, IImageFor
119119
return $"data:{format.DefaultMimeType};base64,{Convert.ToBase64String(stream.ToArray())}";
120120
}
121121
}
122-
123-
/// <summary>
124-
/// Throws <see cref="ObjectDisposedException"/> if the image is disposed.
125-
/// </summary>
126-
internal static void EnsureNotDisposed(this Image image)
127-
{
128-
if (image.IsDisposed)
129-
{
130-
throw new ObjectDisposedException(nameof(image), "Trying to execute an operation on a disposed image.");
131-
}
132-
}
133122
}
134123
}

src/ImageSharp/ImageFrame.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,17 @@ protected ImageFrame(Configuration configuration, int width, int height, ImageFr
7474
public Rectangle Bounds() => new Rectangle(0, 0, this.Width, this.Height);
7575

7676
/// <inheritdoc />
77-
public abstract void Dispose();
77+
public void Dispose()
78+
{
79+
this.Dispose(true);
80+
GC.SuppressFinalize(this);
81+
}
82+
83+
/// <summary>
84+
/// Disposes the object and frees resources for the Garbage Collector.
85+
/// </summary>
86+
/// <param name="disposing">Whether to dispose of managed and unmanaged objects.</param>
87+
protected abstract void Dispose(bool disposing);
7888

7989
internal abstract void CopyPixelsTo<TDestinationPixel>(Span<TDestinationPixel> destination)
8090
where TDestinationPixel : struct, IPixel<TDestinationPixel>;

src/ImageSharp/ImageFrame{TPixel}.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp
2121
/// In all other cases it is the only frame of the image.
2222
/// </summary>
2323
/// <typeparam name="TPixel">The pixel format.</typeparam>
24-
public sealed class ImageFrame<TPixel> : ImageFrame, IPixelSource<TPixel>, IDisposable
24+
public sealed class ImageFrame<TPixel> : ImageFrame, IPixelSource<TPixel>
2525
where TPixel : struct, IPixel<TPixel>
2626
{
2727
private bool isDisposed;
@@ -196,20 +196,20 @@ internal void SwapOrCopyPixelsBufferFrom(ImageFrame<TPixel> pixelSource)
196196
this.UpdateSize(this.PixelBuffer.Size());
197197
}
198198

199-
/// <summary>
200-
/// Disposes the object and frees resources for the Garbage Collector.
201-
/// </summary>
202-
public override void Dispose()
199+
/// <inheritdoc/>
200+
protected override void Dispose(bool disposing)
203201
{
204202
if (this.isDisposed)
205203
{
206204
return;
207205
}
208206

209-
this.PixelBuffer?.Dispose();
210-
this.PixelBuffer = null;
207+
if (disposing)
208+
{
209+
this.PixelBuffer?.Dispose();
210+
this.PixelBuffer = null;
211+
}
211212

212-
// Note disposing is done.
213213
this.isDisposed = true;
214214
}
215215

src/ImageSharp/Image{TPixel}.cs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) Six Labors and contributors.
1+
// Copyright (c) Six Labors and contributors.
22
// Licensed under the Apache License, Version 2.0.
33

44
using System;
@@ -21,6 +21,8 @@ namespace SixLabors.ImageSharp
2121
public sealed class Image<TPixel> : Image
2222
where TPixel : struct, IPixel<TPixel>
2323
{
24+
private bool isDisposed;
25+
2426
/// <summary>
2527
/// Initializes a new instance of the <see cref="Image{TPixel}"/> class
2628
/// with the height and the width of the image.
@@ -185,7 +187,29 @@ public override Image<TPixel2> CloneAs<TPixel2>(Configuration configuration)
185187
}
186188

187189
/// <inheritdoc/>
188-
protected override void DisposeImpl() => this.Frames.Dispose();
190+
protected override void Dispose(bool disposing)
191+
{
192+
if (this.isDisposed)
193+
{
194+
return;
195+
}
196+
197+
if (disposing)
198+
{
199+
this.Frames.Dispose();
200+
}
201+
202+
this.isDisposed = true;
203+
}
204+
205+
/// <inheritdoc/>
206+
internal override void EnsureNotDisposed()
207+
{
208+
if (this.isDisposed)
209+
{
210+
throw new ObjectDisposedException("Trying to execute an operation on a disposed image.");
211+
}
212+
}
189213

190214
/// <inheritdoc />
191215
internal override void AcceptVisitor(IImageVisitor visitor)

src/ImageSharp/Processing/Processors/CloningImageProcessor{TPixel}.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ namespace SixLabors.ImageSharp.Processing.Processors
1515
internal abstract class CloningImageProcessor<TPixel> : ICloningImageProcessor<TPixel>
1616
where TPixel : struct, IPixel<TPixel>
1717
{
18-
private bool isDisposed;
19-
2018
/// <summary>
2119
/// Initializes a new instance of the <see cref="CloningImageProcessor{TPixel}"/> class.
2220
/// </summary>
@@ -104,6 +102,7 @@ public void Apply()
104102
public void Dispose()
105103
{
106104
this.Dispose(true);
105+
GC.SuppressFinalize(this);
107106
}
108107

109108
/// <summary>
@@ -160,10 +159,6 @@ protected virtual void AfterImageApply(Image<TPixel> destination)
160159
/// <param name="disposing">Whether to dispose managed and unmanaged objects.</param>
161160
protected virtual void Dispose(bool disposing)
162161
{
163-
if (!this.isDisposed)
164-
{
165-
this.isDisposed = true;
166-
}
167162
}
168163
}
169164
}

src/ImageSharp/Processing/Processors/ImageProcessor{TPixel}.cs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ namespace SixLabors.ImageSharp.Processing.Processors
1515
internal abstract class ImageProcessor<TPixel> : IImageProcessor<TPixel>
1616
where TPixel : struct, IPixel<TPixel>
1717
{
18-
private bool isDisposed;
19-
2018
/// <summary>
2119
/// Initializes a new instance of the <see cref="ImageProcessor{TPixel}"/> class.
2220
/// </summary>
@@ -97,6 +95,8 @@ public void Apply(ImageFrame<TPixel> source)
9795
/// <inheritdoc/>
9896
public virtual void Dispose()
9997
{
98+
this.Dispose(true);
99+
GC.SuppressFinalize(this);
100100
}
101101

102102
/// <summary>
@@ -142,10 +142,6 @@ protected virtual void AfterImageApply()
142142
/// <param name="disposing">Whether to dispose managed and unmanaged objects.</param>
143143
protected virtual void Dispose(bool disposing)
144144
{
145-
if (!this.isDisposed)
146-
{
147-
this.isDisposed = true;
148-
}
149145
}
150146
}
151147
}

0 commit comments

Comments
 (0)