Испытывание затруднений, избавляющихся от избыточного кода через наследование или дженерики

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

Ситуация, в упрощенной форме, выглядит примерно так. У меня есть набор классов, которые все наследовали от одного типа.

public class Foo : SuperFoo
{
     ...
     public Foo SomeMethod() { ... }
}
public class Bar : SuperFoo
{
     ...
     public Bar SomeMethod() { ... }
}
public class Baz : SuperFoo
{
     ...
     public Baz SomeMethod() { ... }
}
...    
public class SuperFoo
{
     ...
}

Проблема возникает, когда наборы этих объектов должны быть обработаны. Мой первый проект решения (плохое) похож на это:

public void SomeEventHasHappened(...)
{
     ProcessFoos();
     ProcessBars();
     ProcessBazes();
     ...
}

public void ProcessFoos()
{
     ...
     foreach (var foo in fooList)
     {
          ...
          foo.SomeMethod();
     }
}
public void ProcessBars()
{
     ...
     foreach (var bar in barList)
     {
          ...
          bar.SomeMethod();
     }
}

... и так далее. Проблема состоит в том, что в основном весь код в методах ProcessX является тем же кроме типа объектов, на которых управляют. Было бы хорошо консолидировать все их в один метод по очевидным причинам.

Моя первая мысль состояла в том, чтобы просто сделать универсальный Процесс () методом, который взял a List<SuperFoo> в качестве параметра и только продолжите двигаться оттуда. Проблема состоит в том, что универсальный SuperFoo не имеет SomeMethod (), и он не может иметь того, потому что каждый из SomeMethod дочерних классов () имеет различный тип возврата, так наличие переопределений не работает.

5
задан jloubert 28 June 2010 в 21:00
поделиться

2 ответа

Обычно я добавляю интерфейс, работающий с базовыми типами.

interface ISuperFoo
{
    public ISuperFoo SomeMethod() { ... }
}

public class Foo : SuperFoo, ISuperFoo
{
     // concrete implementation
     public Foo SomeMethod() { ... }

     // method for generic use, call by base type
     public ISuperFoo ISuperFoo.SomeMethod() 
     { 
       return SomeMethod(); 
     }
}

public void Processs()
{
     ...
     foreach (var iSuperFoo in list)
     {
          ...
          iSuperFoo.SomeMethod();
     }
}

Конечно, это зависит от того, для чего вы используете результат.

Иногда вы можете упростить использование универсальных шаблонов, но также можете попасть в беспорядок. Иногда проще куда-то унизить. Конечно, вы стараетесь избегать этого, когда можете себе это позволить.

2
ответ дан 15 December 2019 в 00:49
поделиться

Вот пример того, как это могло бы работать с использованием дженериков и превращения SuperFoo в абстрактный класс.

public interface ISuperFoo
{
    ...
}

public abstract class SuperFoo<T> where T : ISuperFoo
{
    public abstract T SomeMethod();
}

public class BazReturn : ISuperFoo
{
    ...
}

public class Baz: SuperFoo<BazReturn>
{
    public override BazReturn SomeMethod()
    {
        throw new NotImplementedException();
    }
}

public class BarReturn : ISuperFoo
{
    ...
}

public class Bar : SuperFoo<BarReturn>
{
    public override BarReturn SomeMethod()
    {
        throw new NotImplementedException();
    }
}

public static class EventHandler
{
    public static void SomeEventHasHappened(List<SuperFoo<ISuperFoo>> list)
    {
        foreach (SuperFoo<ISuperFoo> item in list)
        {
            ISuperFoo result = item.SomeMethod();
        }
    }
}

Вы можете заменить интерфейс ISuperFoo на конкретный класс, если это необходимо, но тогда вам придется приводить возвращаемое значение, что противоречит цели.

public abstract class SuperFoo<T>
{
    public abstract T SomeMethod();
}

public class Foo : SuperFoo<int>
{
    public override int SomeMethod()
    {
        throw new NotImplementedException();
    }
}

public static class EventHandler
{
    public static void SomeEventHasHappened(List<SuperFoo<int>> list)
    {
        foreach (SuperFoo<int> item in list)
        {
            item.SomeMethod();
        }
    }
}
2
ответ дан 15 December 2019 в 00:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: