2011-11-29 9 views
5

Estoy tratando de implementar un patrón de filtro/canalización para poder tomar una entrada, procesarla a través de una serie de filtros y obtener una salida al final.Tubería genérica donde los tipos de entrada/salida son diferentes para cada filtro

Puedo hacer esto fácilmente cuando el tipo de entrada y los tipos de salida final son los mismos y cada filtro usa los mismos tipos también. Sin embargo, quiero ingresar un tipo y obtener otro tipo.

p. Ej. Tome un archivo csv por su nombre de archivo, cárguelo en una cadena individual, analícelos, valídelos y déjelos como xml. ejemplo pseudo código:

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 

Esto es lo que tengo hasta ahora:

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

Mi intención era la de ser capaz de tener una lista de IFilter<T,U> donde T and U are IBusinessObject

Sin embargo, aparece un " No se puede convertir de BusinessObjectImplementation a IBusinessObject "al intentar agregar un IFilter<IBusinessObject, IBusinessObject> a la lista.

apols para todo el código ... Es la última parte que no se compilará


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

La excepción está en la línea .Register por encima de

error 2 Argumento 1: no se puede convertir de 'BusinessLogic.FilterCsvFileLoader<BusinessObjects.FilenameObject,BusinessObjects.CSVFile>' a 'BusinessLogic.IFilter<BusinessObjects.IBusinessObject,BusinessObjects.IBusinessObject>'
C: \ Users \ \ davidc documentos \ Visual Studio 2010 \ Projects \ MPMeFeed \ TestConsole \ Program.cs 15 23 TestConsole

Respuesta

5

El problema que tenemos aquí es que FilterCsvFileLoader<FilenameObject, CSVFile> implementos IFilter<FilenameObject, CSVFile> que no es un tipo derivado de IFilter<IBusinessObject, IBusinessObject> a pesar de que FilenameObject & CSVFile se derivan de IBusinessObject.

Esto es un error común de hacer.

intentar algo como esto en su lugar:

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

Gracias, y una buena explicación de por qué esto no funcionó. – BlueChippy

0

me parece que cada vez que me encuentro con una situación en la que muchos desconocidos o impredecibles tipos están involucrados nuestro amigo object entra en juego. Eso puede funcionar para ti.

puede tardar algo de investigación de su parte, pero hay una aplicación tubería genérica en los conjuntos básicos de infraestructura utilizados por mi bus de servicio:

http://shuttle.codeplex.com/

La clase es ObservablePipeline en el montaje Shuttle.Core.infrastructure

Puede darte algunas ideas.

Cuestiones relacionadas