Skip to content

Commit a8184e7

Browse files
sealed classes
1 parent e731020 commit a8184e7

File tree

3 files changed

+17
-9
lines changed

3 files changed

+17
-9
lines changed

README.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
# Simple TPL Dataflow Pipelines
44

5+
[![Nuget](https://img.shields.io/nuget/v/SimpleTplDataflowPipelines)](https://www.nuget.org/packages/SimpleTplDataflowPipelines/)
6+
57
This library helps at building simple [TPL Dataflow](https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/dataflow-task-parallel-library) pipelines,
68
that enforce the following guarantees:
79

@@ -100,15 +102,15 @@ the `Completion` property of the individual blocks. Observing this exception jus
100102
this block was not the first that failed. It is possible that the `PipelineException`
101103
may coexist with other exceptions in the same dataflow block.
102104

103-
## Discussion
105+
## Comparison with Encapsulate
104106

105107
It might be helpful to compare the functionality offered by this library with the
106108
functionality offered by the [`DataflowBlock.Encapsulate`](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.dataflow.dataflowblock.encapsulate) method.
107109
The result of this method is similar with the result of the `ToPipeline` method: both return
108110
an [`IPropagatorBlock<TInput, TOutput>`](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.dataflow.ipropagatorblock-2) implementation
109111
(a block that is both a target and a source). The `DataflowBlock.Encapsulate`
110112
accepts a `target` and a `source` block, and returns a propagator that delegates to
111-
these two blocks. The two blocks are not linked automatically in any way, and the completion
113+
these two blocks. The two blocks are **not** linked automatically in any way, and the completion
112114
of the propagator represents the completion of the second (the `source`) block only.
113115
On the contrary the `ToPipeline` returns a propagator that links all the dataflow
114116
blocks tightly in both directions, and its `Completion` represents the completion of all its
@@ -129,7 +131,6 @@ bool received = receivable.TryReceive(out string item);
129131
## Embedding the library into your project
130132

131133
You can install the [SimpleTplDataflowPipelines](https://www.nuget.org/packages/SimpleTplDataflowPipelines/) NuGet package.
132-
[![Nuget](https://img.shields.io/nuget/v/SimpleTplDataflowPipelines)](https://www.nuget.org/packages/SimpleTplDataflowPipelines/)
133134
You can also [download](https://github.com/theodorzoulias/SimpleTplDataflowPipelines/releases) the project and build it locally, or just
134135
embed the single code file [`PipelineBuilder.cs`](https://github.com/theodorzoulias/SimpleTplDataflowPipelines/blob/main/src/SimpleTplDataflowPipelines/PipelineBuilder.cs)
135136
(~400 lines of code) into your project.

src/SimpleTplDataflowPipelines/PipelineBuilder.cs

+12-5
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ internal delegate Action LinkDelegate(
4040
/// <summary>
4141
/// Represents an error that occurred in an other dataflow block, owned by the same pipeline.
4242
/// </summary>
43-
public class PipelineException : Exception
43+
public sealed class PipelineException : Exception
4444
{
45+
// Prevent this type from being publicly creatable.
4546
internal PipelineException() : base("An other dataflow block, owned by the same pipeline, failed.") { }
4647
}
4748

@@ -201,9 +202,15 @@ internal static Task CreatePipeline<TInput>(ITargetBlock<TInput> target,
201202
return Task.WhenAll(completions).ContinueWith(t =>
202203
{
203204
if (!t.IsFaulted) return t;
205+
206+
// Propagate all non-PipelineException errors.
207+
// At least one should exist, unless reflection was used.
208+
var filtered = t.Exception.InnerExceptions
209+
.Where(ex => !(ex is PipelineException));
210+
if (!filtered.Any()) throw new InvalidOperationException(
211+
"After filtering out the PipelineExceptions, no other exception was left.");
204212
var tcs = new TaskCompletionSource<object>();
205-
tcs.SetException(
206-
t.Exception.InnerExceptions.Where(ex => !(ex is PipelineException)));
213+
tcs.SetException(filtered);
207214
return tcs.Task;
208215
}, default(CancellationToken), TaskContinuationOptions.DenyChildAttach, TaskScheduler.Default).Unwrap();
209216
}
@@ -301,7 +308,7 @@ internal static T[] Append<T>(T[] array, T item)
301308
}
302309
}
303310

304-
internal class Pipeline<TInput> : ITargetBlock<TInput>
311+
internal sealed class Pipeline<TInput> : ITargetBlock<TInput>
305312
{
306313
private readonly ITargetBlock<TInput> _target;
307314
private readonly Task _completion;
@@ -323,7 +330,7 @@ public DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader,
323330
=> _target.OfferMessage(messageHeader, messageValue, source, consumeToAccept);
324331
}
325332

326-
internal class Pipeline<TInput, TOutput> : IPropagatorBlock<TInput, TOutput>,
333+
internal sealed class Pipeline<TInput, TOutput> : IPropagatorBlock<TInput, TOutput>,
327334
IReceivableSourceBlock<TOutput>
328335
{
329336
private readonly ITargetBlock<TInput> _target;

src/SimpleTplDataflowPipelines/SimpleTplDataflowPipelines.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<TargetFrameworks>netstandard2.0;net46</TargetFrameworks>
55
<Authors>Theodor Zoulias</Authors>
66
<Description>A library that helps at building simple TPL Dataflow pipelines</Description>
7-
<Version>1.0.7</Version>
7+
<Version>1.1.0</Version>
88
<GenerateDocumentationFile>true</GenerateDocumentationFile>
99
<PackageLicenseFile>LICENSE</PackageLicenseFile>
1010
<PackageIcon>logo_32.png</PackageIcon>

0 commit comments

Comments
 (0)