Общий конвейер, в котором типы ввода / вывода различны для каждого фильтра - PullRequest
6 голосов
/ 29 ноября 2011

Я пытаюсь реализовать шаблон Filter / Pipeline, чтобы я мог взять вход, обработать его через несколько фильтров и получить вывод в конце.

Я могу сделать это легко, когда входТип и окончательный тип выходных данных одинаковы, и каждый фильтр использует одинаковые типы.Однако я хочу ввести один тип и получить другой тип.

Например, взять csvfile по имени файла, загрузить его в отдельную строку, проанализировать их, проверить и вывести как xml.Пример кода psuedo:

input = filename
filter = load csv file <filename, list<string>>
filter = parse csv <list<string>, list<businessobject>>
filter = validate objects <list<businessobject>, list<businessobject>> *... return type same as input type in this case.*
filter = create xml <list<businessobject>, XDocument>
filter = validate XDoc <XDocument, XDocument>
output = XDocument

Вот что я имею до сих пор:

IFilter, FilterBase, FilterImplementation
IPipeline, Pipeline
IBusinessObject, BusinessObject, BusinessObjectImplementation

Мое намерение состояло в том, чтобы иметь возможность иметь список IFilter<T,U>, где T and U are IBusinessObject

Тем не менее, я получаю «Невозможно преобразовать из BusinessObjectImplementation в IBusinessObject» при попытке добавить IFilter<IBusinessObject, IBusinessObject> в список.

Apols для всего кода ... это оченьпоследняя часть, которая не будет компилироваться


public interface IFilter<T, U>
        where T : IBusinessObject
        where U : IBusinessObject
    {
        U Execute(T input);
    }

    public abstract class FilterBase<T, U> : IFilter<T, U>
        where T : IBusinessObject
        where U : IBusinessObject, new()
    {
        protected abstract U Process(T input);

        public U Execute(T input)
        {
            return Process(input);
        }

    }

    public class FilterCsvFileLoader<T, U> : FilterBase<T, U>, IFilter<T, U>
        where T : FilenameObject, IBusinessObject
        where U : CSVFile, IBusinessObject, new()
    {
        public FilterCsvFileLoader()
        { }

        protected override U Process(T input)
        {
            U result = new CSVFile(input) as U;
            return result;
        }
    }

public interface IPipeline
    {
        IBusinessObject Execute(IBusinessObject input);

        IPipeline Register(IFilter<IBusinessObject, IBusinessObject> filter);
    }

    public class Pipeline : IPipeline
    {
        private List<IFilter<IBusinessObject, IBusinessObject>> _filters = new List<IFilter<IBusinessObject, IBusinessObject>>();

        public IBusinessObject Execute(IBusinessObject input)
        {
            var result = input;
            foreach (var filter in _filters)
            {
                result = filter.Execute(result);
            }
            return result;
        }

        public IPipeline Register(IFilter<IBusinessObject, IBusinessObject> filter)
        {
            _filters.Add(filter);
            return this;
        }
    }

public interface IBusinessObject
    {
        bool Validate();
        List<string> ValidationErrors { get; }
    }

    public class BusinessObject : IBusinessObject
    {
        private List<BusinessRule> _businessRules = new List<BusinessRule>();

        private List<string> _validationErrors = new List<string>();

        public List<string> ValidationErrors
        {
            get { return _validationErrors; }
        }
        protected void AddRule(BusinessRule rule)
        {
            _businessRules.Add(rule);
        }

        public bool Validate()
        {
            bool isValid = true;

            _validationErrors.Clear();

            foreach (BusinessRule rule in _businessRules)
            {
                if (!rule.Validate(this))
                {
                    isValid = false;
                    _validationErrors.Add(rule.ErrorMessage);
                }
            }
            return isValid;
        }
    }

    public class FilenameObject : BusinessObject, IBusinessObject
    {
        string _filename;

        public string Filename
        {
            get { return _filename; }
        }

        public FilenameObject(string filename)
        {
            _filename = filename;
        }
    }

    public class CSVFile : BusinessObject, IBusinessObject
    {
        private string _filename;
        private string[] _splitChar = new string[] { "," };

        public List<List<string>> Lines { get; set; }

        public CSVFile()
        { }

        public CSVFile(FilenameObject filename)
            : this()
        {
            _filename = filename.Filename;
            Lines = new List<List<string>>();
        }

        private void ImportFile()
        {
            FileInfo fi = new FileInfo(_filename);
            using (StreamReader sr = new StreamReader(fi.Open(FileMode.Open, FileAccess.Read, FileShare.None)))
            {
                String readline;
                while ((readline = sr.ReadLine()) != null)
                {
                    var line = (from l in readline.Split(_splitChar, StringSplitOptions.None)
                                select l.Trim()).ToList();
                    Lines.Add(line);
                }
            }
        }
    }

class Program
    {
        static void Main(string[] args)
        {
            var pipeline = new Pipeline()
            .Register(new FilterCsvFileLoader<FilenameObject, CSVFile>());
        }
    }

Исключение составляет строка .Register выше

Ошибка 2 Аргумент 1: невозможно преобразовать из 'BusinessLogic.FilterCsvFileLoader<BusinessObjects.FilenameObject,BusinessObjects.CSVFile>' в 'BusinessLogic.IFilter<BusinessObjects.IBusinessObject,BusinessObjects.IBusinessObject>'
C: \ Users \ davidc \ Documents \ Visual Studio 2010 \ Projects \ MPMeFeed \TestConsole \ Program.cs 15 23 TestConsole

Ответы [ 2 ]

6 голосов
/ 29 ноября 2011

Ваша проблема в том, что FilterCsvFileLoader<FilenameObject, CSVFile> реализует IFilter<FilenameObject, CSVFile>, который НЕ является производным типом IFilter<IBusinessObject, IBusinessObject>, хотя FilenameObject & CSVFile получены из IBusinessObject.

Это распространенная ошибка.

Попробуйте что-то вроде этого:

public interface IFilter
{
    IBusinessObject Execute(IBusinessObject input);
}

public interface IFilter<T, U> : IFilter
    where T : IBusinessObject
    where U : IBusinessObject
{
    U Execute(T input);
}

public abstract class FilterBase<T, U> : IFilter<T, U>
    where T : IBusinessObject
    where U : IBusinessObject, new()
{
    protected abstract U Process(T input);

    IBusinessObject IFilter.Execute(IBusinessObject input)
    {
        return this.Execute((T)input);
    }

    public U Execute(T input)
    {
        return Process(input);
    }
}

public interface IPipeline
{
    IBusinessObject Execute(IBusinessObject input);

    IPipeline Register<T, U>(IFilter<T, U> filter)
        where T : IBusinessObject
        where U : IBusinessObject;
}

public class Pipeline : IPipeline
{
    private List<IFilter> _filters = new List<IFilter>();

    public IBusinessObject Execute(IBusinessObject input)
    {
        var result = input;
        foreach (var filter in _filters)
        {
            result = filter.Execute(result);
        }
        return result;
    }

    public IPipeline Register<T, U>(IFilter<T, U> filter)
        where T : IBusinessObject
        where U : IBusinessObject
    {
        _filters.Add(filter);
        return this;
    }
}
0 голосов
/ 29 ноября 2011

Я обнаруживаю, что всякий раз, когда я сталкиваюсь с ситуацией, в которой участвует много неизвестных или непредсказуемых типов, наш друг object вступает в игру.Это может сработать для вас.

Может потребоваться некоторое копание с вашей стороны, но в сборках базовой инфраструктуры, используемых моей служебной шиной, есть общая конвейерная реализация:

http://shuttle.codeplex.com/

Класс ObservablePipeline в сборке Shuttle.Core.infrastructure

Может дать вам несколько идей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...