开发者

How to make derived class function be executed?

开发者 https://www.devze.com 2023-04-10 12:00 出处:网络
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

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 "filt开发者_StackOverflower";
  }

  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:

  • filter
  • filter
  • ...

How do I get it to print this instead?

  • distr filter
  • distr filter
  • ...


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.


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


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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号