Как заставить функцию производного класса выполняться? - PullRequest
3 голосов
/ 01 октября 2011

У нас есть базовый класс: фильтр. DistrFilter и ReportFilter наследуются от Filter.

В другом классе, FilterService.cs, у нас есть две функции, которые принимают эти три типа классов. FilterService работает с объектами Filter, но не наследует ничего.

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

Тогда это печатает:

  • фильтр
  • фильтр

Как мне заставить его напечатать это вместо этого?

  • фильтр distr
  • фильтр distr

Ответы [ 3 ]

2 голосов
/ 01 октября 2011

Добавьте виртуальный метод к классу Filter, называемый GetName() или чем-то подобным, и реализуйте его как return "distr filter"; в DistrFilter и как return "report filter"; в ReportFilter. Тогда просто позвоните f.GetName() в GetDesc().

В качестве альтернативы, вы можете использовать проверки, подобные if (f is DistrFilter) в GetDesc(), но такая структура, явно проверяющая определенные производные классы и обрабатывающая их по-разному, обычно считается плохим проектом.

1 голос
/ 01 октября 2011

Либо реализуйте GetFilterText() как виртуальный метод в 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"; }
}

Тогда сделайте это:

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

Или, если вы хотите отделить задачу определения текста фильтра от классов Filter, используйте двойную диспетчеризацию (шаблон посетителя). Это полезно, если у вас могут быть разные типы сервисов фильтрации. Это можно сделать следующим образом:

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

Тогда к вашим услугам:

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

Некоторые ссылки: Двойная отправка , Шаблон посетителей

1 голос
/ 01 октября 2011

Реализуйте шаблон, который делает что-то вроде этого:

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