2012-10-31 21 views
13

TPL Dataflow cung cấp một TransformBlock cho chuyển đầu vào, ví dụ .:Bỏ qua mục trong Dataflow TransformBlock

var tb = new TransformBlock<int, int>(i => i * 2); 

Có thể không ra một số đầu vào, ví dụ nếu đầu vào thất bại một số kiểm tra xác nhận?

var tb = new TransformBlock<InputType, OutputType>(i => 
{ 
    if (!ValidateInput(i)) 
    { 
     // Do something to not output anything for this input 
    } 
    // Normal output 
} 

Nếu điều đó là không thể, thì mẫu tốt nhất để đạt được mục tiêu đó là gì?
Điều gì đó như sau?

BufferBlock<OutputType> output = new BufferBlock<OutputType>(); 

var ab = new ActionBlock<InputType>(i => 
{ 
    if (ValidateInput(i)) 
    { 
     output.Post(MyTransform(i)); 
    } 
} 

Trả lời

11

Có một số tùy chọn về cách để làm điều này:

  1. Sử dụng TransformManyBlock như Jon gợi ý và trả về một bộ sưu tập có chứa 1 hoặc 0 mặt hàng.
  2. Sử dụng TransformBlock với một số giá trị đặc biệt đại diện cho “không có giá trị” (ví dụ: null) và sau đó sử dụng LinkTo() với bộ lọc để xóa những giá trị đó. Bạn cũng phải liên kết các TransformBlock để khối rỗng (DataflowBlock.NullTarget<T>()) mà không có bộ lọc, để thoát các giá trị đặc biệt.
  3. tôi sẽ xem xét một cái gì đó của một hack, nhưng bạn cũng có thể sử dụng Task constructor dựa trên các TransformBlock: sử dụng Task.FromResult() khi bạn muốn quay trở lại một cái gì đó và null khi bạn thì không. Ví dụ:

    new TransformBlock<int, int>(i => i % 2 == 0 ? Task.FromResult(i * 2) : null) 
    
8

tôi đã không sử dụng dataflow bản thân mình, nhưng tôi nghĩ bạn có thể sử dụng một TransformManyBlock, và chỉ cần thực hiện từng bước trở lại hoặc là một bộ sưu tập sản phẩm nào hoặc một mục duy nhất.

var tmb = new TransformManyBlock<InputType, OutputType>(i => 
{ 
    if (!ValidateInput(i)) 
    { 
     return Enumerable.Empty<OutputType>(); 
    } 
    ... 
    // Or return new[] { outputValue }; 
    return Enumerable.Repeat(outputValue, 1); 
}); 

Bạn thậm chí có thể có khả năng khái quát này cho một người FilterBlock<T>chỉ có một vị bộ lọc, và vượt qua các trận đấu thích hợp thông qua (giống như Where trong LINQ). Ban đầu bạn có thể thực hiện điều này bằng cách sử dụng TransformManyBlock như trên, nhưng sau đó làm cho nó hiệu quả hơn sau này.

1

Một chút câu hỏi cũ, muốn thêm một số kinh nghiệm ở đây: bạn có thể giới thiệu một BufferBlock thay vì ActionBlock cho dữ liệu của bạn, và sử dụng phương pháp mở rộng LinkTo với điều kiện vị, do đó hợp lệ các giá trị sẽ tiến tới TransformBlock và các giá trị không hợp lệ sẽ bị bỏ qua. Để loại bỏ chúng, bạn có thể chỉ cần sử dụng khối NullTarget, đơn giản là bỏ qua dữ liệu mà nó nhận được. Vì vậy, các mã cuối cùng có thể nhìn như thế này:

var input = new BufferBlock<int>(); 
var tb = new TransformBlock<int, int>(i => i * 2); 
var output = new BufferBlock<int>(); 

// valid integers will pass to the transform 
input.LinkTo(tb, i => ValidateInput(i)); 

// not valid will be discarded 
input.LinkTo(DataflowBlock.NullTarget<int>()); 

// transformed data will come to the output 
tb.LinkTo(output); 

Cũng liên kết có thể được điều chỉnh với một số DataflowLinkOptions với other LinkTo overload.

+0

Đây là lựa chọn cơ bản (2) trong câu trả lời của svick. –

+0

@GordonBean có thêm liên kết trực tiếp giữa các khối – VMAtm

Các vấn đề liên quan