2011-11-29 11 views
5

Sto tentando di implementare un pattern Filtro/Pipeline in modo che possa ricevere un input, elaborarlo attraverso un numero di filtri e ottenere un output alla fine.Pipeline generica in cui i tipi di input/output sono diversi per ciascun filtro

Posso farlo facilmente quando il tipo di input e il tipo di output finale sono gli stessi e ogni filtro usa gli stessi tipi. Tuttavia, voglio inserire un tipo e ottenere un altro tipo.

ad es. Prendete un file csv dal suo nome file, caricatelo in una stringa singola, analizzatelo, convalidate e uscite come xml. Codice pseudo esempio:

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 

Ecco quello che ho finora:

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

La mia intenzione era quella di essere in grado di avere una lista di IFilter<T,U> dove T and U are IBusinessObject

Tuttavia, ho un " Impossibile convertire da BusinessObjectImplementation a IBusinessObject "quando si tenta di aggiungere un IFilter<IBusinessObject, IBusinessObject> all'elenco.

Apols per tutto il codice ... la sua l'ultima parte che non verrà compilato


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>()); 
     } 
    } 

L'eccezione è sulla linea .Register sopra

Errore 2 Argomento 1: non può convertire da 'BusinessLogic.FilterCsvFileLoader<BusinessObjects.FilenameObject,BusinessObjects.CSVFile>' a 'BusinessLogic.IFilter<BusinessObjects.IBusinessObject,BusinessObjects.IBusinessObject>'
C: \ Users \ \ davidc Documents \ visiva Studio 2010 \ Projects \ MPMeFeed \ TestConsole \ Program.cs 15 23 TestConsole

risposta

5

Il problema che hai qui è che FilterCsvFileLoader<FilenameObject, CSVFile> implementa IFilter<FilenameObject, CSVFile> che non è un tipo derivato di IFilter<IBusinessObject, IBusinessObject> anche se FilenameObject & CSVFile sono derivati ​​da IBusinessObject.

Questo è un errore comune da fare.

provare qualcosa di simile, invece:

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

Grazie, e una buona spiegazione del perché questo non ha funzionato. – BlueChippy

0

trovo che ogni volta che mi imbatto in una situazione in cui molti sconosciuti o imprevedibili i tipi sono coinvolti il ​​nostro amico object entra in gioco. Potrebbe funzionare per te.

Si può richiedere un po 'scavare da parte vostra, ma c'è un'implementazione gasdotto generica nelle assemblee di base delle infrastrutture utilizzate dal mio autobus del servizio:

http://shuttle.codeplex.com/

La classe è ObservablePipeline in assemblea Shuttle.Core.infrastructure

Potrebbe darti qualche idea.

Problemi correlati