
A co jeżeli chcielibyśmy stworzyć pipeline z innym typem wejścia i wyjścia? Wtedy będziesz musiał zastosować type dynamic. Spójrz na klasę podstawową reprezentującą dany krok, która została przedstawiona w poprzednim rozwiązaniu:
public abstract class BaseStep<T>
{
protected BaseStep<T> _nextStep;
public void SetNextStep(BaseStep<T> nextStep)
{
_nextStep = nextStep;
}
public T Process(T input)
{
var items = Handle(input);
return _nextStep != null ? _nextStep.Process(items) : items;
}
protected abstract T Handle(T input);
}
Zmieńmy w tej klasie type dla następnego kroku, wprowadźmy dodatkowy parametr generyczny, aby odróżnić typ wejściowy od wyjściowego.
Cała klasa bazowa musi dziedziczyć po DynamicObject.
public abstract class ProceseBase<T, TReturn> : DynamicObject
{
protected dynamic _nextStep;
public void SetNextStep(dynamic nextStep)
{
_nextStep = nextStep;
}
public dynamic Process(T input)
{
var items = Handle(input);
return _nextStep != null ? _nextStep.Process(items) : items;
}
protected abstract TReturn Handle(T input);
}
Taka zmiana pozwoli nam na dowolną modyfikację zwracanych typów obiektu z pipeline.

Przykład użycia wygląda następująco. Dajmy na to, że z wygenerowanych licz, chcemy sprawdzić ile jest licz dla danej pierwszej cyfrą. Dla liczb { 1,11,13,29,32,300 } mamy dla cyfry 1 - 3 liczby, dla 2 - 1 liczba, dla 3 - 2 liczby.
Na samym początku stwórzmy klasę, która będzie reprezentowała pierwszy krok - konwersja na string.
public class ConvertToStringProcess<T>
: ProceseBase<IEnumerable<T>, IEnumerable<string>>
{
protected override IEnumerable<string> Handle(IEnumerable<T> input)
{
return input.Select(x => x.ToString());
}
}
Następnie krok grupujący oraz krok zliczający liczbę elementów. Każdy z tych kroków ma inny typ wejściowy i wyjściowy.
public class GroupByFirstCharProcess
: ProceseBase<IEnumerable<string>, IEnumerable<IGrouping<char,string>>>
{
protected override IEnumerable<IGrouping<char, string>>
Handle(IEnumerable<string> input)
{
return input.GroupBy(x => x.First());
}
}
public class CountItemsDictionary
: ProceseBase<IEnumerable<IGrouping<char, string>>, Dictionary<char, int>>
{
protected override Dictionary<char, int>
Handle(IEnumerable<IGrouping<char, string>> input)
{
return input.ToDictionary(x => x.Key, x => x.Count());
}
}
A na końcu wywołanie dynamic pipelinu. Każde rozwiązanie ma jakieś plusy i minusy. W tym rozwiązaniu minusem jest używanie dynamikc :)
(tutaj, tutaj i tutaj)
var numbers= HelpClass.GenerateData<int>(x => x * x).Take(300); dynamic itemsStrings= new ConvertToStringProcess<int>(); GroupByFirstCharProcess groupedByFirstChar = new GroupByFirstCharProcess(); CountItemsDictionary countedItems = new CountItemsDictionary(); itemsStrings.SetNextStep(groupedByFirstChar); groupedByFirstChar.SetNextStep(countedItems); var countedNumbers= itemsStrings.Process(numbers);
Brak komentarzy:
Prześlij komentarz