Bill Paetzke
Bill Paetzke

Reputation: 13572

How to make derived class function be executed?

We have a base class: Filter. DistrFilter and ReportFilter inherit from Filter.

In another class, FilterService.cs, we have two functions that accept these three class types. FilterService operates on Filter objects but it does not inherit from anything.

public class FilterService
{

  public string GetDesc(List<T> filters) where T : Filter
  {
     if(filters.Count == 0) return String.Empty;

     StringBuilder s = new StringBuilder("<ul>");
     foreach (T f in filters)
         s.AppendFormat("<li>{1}</li>", GetFilterText(f));

     s.Append("</ul>");

     return s.ToString();
  }

  public string GetFilterText(Filter f)
  {
     return "filter";
  }

  public string GetFilterText(DistrFilter f)
  {
     return "distr filter";
  }

  public string GetFilterText(ReportFilter f)
  {
     return "report filter";
  }
}

public static void main(string[] args)
{
   List<DistrFilter> distrFilters = new List<DistrFilters>();
   distrFilters.Add(new DistrFilter());
   distrFilters.Add(new DistrFilter());
   distrFilters.Add(new DistrFilter());

   FilterService fs = new FilterService();
   Console.WriteLine(fs.GetDescription(distrFilters));
}

Then it prints:

How do I get it to print this instead?

Upvotes: 3

Views: 126

Answers (3)

Ilian
Ilian

Reputation: 5355

Either implement GetFilterText() as a virtual method in Filter:

class Filter
{
    // Can be converted into a property as well.
    public virtual string GetFilterText { return "filter"; }
}

class DistrFilter : Filter
{
    public override string GetFilterText { return "distr filter"; }
}

Then do this:

StringBuilder s = new StringBuilder("<ul>");
foreach (T f in filters)
    s.AppendFormat("<li>{0}</li>", f.GetFilterText());

Or if you want to separate the concern of specifying the filter text from the Filter classes, use double dispatch (visitor pattern). This is useful if you can have different types of filter services. This can be done this way:

interface IServiceAcceptor
{
    string Accept(FilterService service);
}

public class Filter : IServiceAcceptor
{
    string IServiceAcceptor.Accept(FilterService service)
    {
        return service.GetFilterText(this);
    }   
}

public class DistrFilter : Filter, IServiceAcceptor
{
    string IServiceAcceptor.Accept(FilterService service)
    {
        return service.GetFilterText(this);
    }       
}

public class ReportFilter : Filter, IServiceAcceptor
{
    string IServiceAcceptor.Accept(FilterService service)
    {
        return service.GetFilterText(this);
    }       
}

Then in your service:

  public string GetDesc<T>(List<T> filters) where T : IServiceAcceptor
  {
     if(filters.Count == 0) return String.Empty;

     var s = new StringBuilder("<ul>");
     foreach (T f in filters)
         s.AppendFormat("<li>{0}</li>", f.Accept(this));

     s.Append("</ul>");

     return s.ToString();
  }

Some references: Double dispatch, Visitor Pattern

Upvotes: 1

Wyzard
Wyzard

Reputation: 34563

Add a virtual method to the Filter class, called GetName() or something similar, and implement it as return "distr filter"; in DistrFilter and as return "report filter"; in ReportFilter. Then just call f.GetName() in GetDesc().

Alternatively, you could use checks like if (f is DistrFilter) in GetDesc(), but that sort of structure, explicitly checking for specific derived classes and handling them differently, is generally considered poor design.

Upvotes: 2

Paul Walls
Paul Walls

Reputation: 6044

Implement a pattern that does something like this:

public class Filter
{
    public virtual string GetDescription()
    {
        return "filter";
    }
}

public class DistrFilter : Filter
{
    public override string GetDescription()
    {
        return "distr filter";
    }
}
public class ReportFilter : Filter
{
    public override string GetDescription()
    {
        return "report filter";
    }
}

public class FilterService
{
    public string GetDescription<T>( List<T> filters )
        where T: Filter
    {
        if ( filters.Count == 0 )
            return String.Empty;

        StringBuilder s = new StringBuilder( "<ul>" );
        foreach ( T f in filters )
            s.AppendFormat( "<li>{0}</li>", f.GetDescription() );

        s.Append( "</ul>" );

        return s.ToString();
    }
}

Upvotes: 1

Related Questions