2009-01-22 9 views
2

У меня есть 100 классов, которые имеют некоторые подобные элементы и некоторые уникальные. Я создал интерфейс, который называет те похожие элементы, например: interface IAnimal. Что я обычно это:Рассматривайте класс так, как если бы он был определен с помощью интерфейса

class dog : IAnimal 

Но есть 100 классов, и я не чувствую, что происходит, хотя их все и ищет тех, что я могу применить IAnimal к.

Что я хочу сделать это:

dog scruffy = new dog(); 
cat ruffles = new cat(); 

IAnimal[] animals = new IAnimal[] {scruffy as IAnimal, ruffles as IAnimal} // gives null 

или

IAnimal[] animals = new IAnimal[] {(IAnimal)scruffy, (IAnimal)ruffles} //throws exception 

затем сделать

foreach (IAnimal animal in animals) 
{ 
    animal.eat(); 
} 

Есть ли способ сделать C# позвольте мне лечить оборками и неряшливо, как IAnimal без необходимости писать: IAnimal при написании класса.

Спасибо!

EDIT (не ленивый): классы генерируются из sql хранимых метаданных proc, что означает, что каждый раз, когда он генерируется, мне нужно будет вернуться и добавить их или изменить генератор кода для идентификации членов, которые в интерфейсе, на самом деле это не плохая идея. Я надеялся, что есть какой-то дженериковый подход или что-то еще.

+0

Модифицировать генератор кода, вероятно, путь. Если он генерирует метод «eat()», в любом случае должно быть тривиально, чтобы этот класс реализовал некоторый интерфейс. –

+0

Да, решение состоит в том, чтобы модифицировать генератор кода. В настоящее время он слишком упрощен для ваших нужд. –

ответ

6

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

+0

Хорошее мышление .. могло бы быть хорошим решением, если сменить генератор кода слишком сложно –

+0

очень приятное решение, мы используем его с сгенерированным кодом – orip

+0

Отражение было классной идеей, но kludgy, это было намного проще в реализации – rizzle

4

Решение состоит в изменении генератора кода. В настоящее время он слишком упрощен для ваших нужд. Он должен добавить реализацию интерфейса, если соответствующие свойства и/или методы присутствуют в классе.

+0

Я не так уж ленив, см. Edit – rizzle

+0

Хорошо, но в вашем первоначальном вопросе вы только что сказали: «У меня 100 классов», вы ничего не сказали о том, что они были сгенерированы автоматически. –

+0

ОК, сделанный пункт. Теперь мой ответ был отредактирован, чтобы отразить отредактированное изменение в вопросе. –

0

№ Нет. Вы не можете получить C#, чтобы позволить вам сделать это, не имея конкретного базового класса или имеющего интерфейс.

10

То, о чем вы просите, называется утиная печать и не является частью C#. Я боюсь. Любое решение будет включать в себя размышления и взгляды на свойства. Я думаю, что быстрее будет проверять классы вручную.

Было бы интересным проектом попробовать.

1

Предполагая, что вы действительно не можете изменить класс кошки по уважительным причинам,

Вы можете написать адаптер для кота, унаследованный от IAnimal т.е.

class cat_adapter : IAnimal 
    { 
     private cat baseCat; 
     public cat_adapter(cat aCat) 
     { 
      baseCat = aCat; 
     } 

     // Implement IAnimal interface and redirect to baseCat 
     public void eat() 
     { 
      baseCat.munchOnMeowMix(); 
     } 

    } 

В C++ можно использовать шаблоны, предполагая все ваши созданные классы должны иметь ту же функцию:

template <class BaseType> 
    class CAnimalAdapter : public IAnimal 
    { 
    private: 
     BaseType* m_baseInstance; 
    public: 
     CAnimalAdapter(BaseType* baseInstance) : 
      m_baseInstance(baseInstance) 
     { 
     } 

     void eat() 
     { 
      // You will get a compiler error if BaseType doesn't have this implemented 
      baseInstance->doEat();     
     } 

    } 

Возможно, кто-то более C# -py, чем я, может сделать то же самое с отражением.

+0

Но тогда вам придется пройти через 100 классов и написать адаптер для каждого. Гораздо больше работы, чем просто поместить ': IAnimal' после этих классов. –

+0

-1 Потому что вы удваиваете классы, но не получаете никакой пользы. –

+0

Уверенный, если у вас нет возможности изменить класс cat, и вам нужно поместить его в свою структуру. –

1

Не легко, что я знаю, вы могли бы совершить последний вызов привязки с использованием отражения, но вы бы лучше потратили свое время на редактирование классов или написание макроса для этого.

0

Если вы уже внедрили этот метод и хотите реализовать интерфейс, вы можете использовать регулярное выражение с заменой в команде files в своей среде IDE.

В противном случае ознакомьтесь с методами расширения. Они могут соответствовать вашим потребностям.

+0

Я думаю, что это было бы довольно сложно сделать только с регулярным выражением. –

+0

Вы в основном выполняете поиск по «class \ w *» и затем добавляете «: IAnimal». –

+0

Тем более, что он должен будет изучить методы и свойства каждого класса, чтобы убедиться, действительно ли он реализует данный интерфейс. –

0

Ваши классы должны реализовать интерфейс IAnimal. Метод/свойство с тем же именем на двух разных классах не считается эквивалентным, если только они не являются реализациями интерфейса/базового класса.

0

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

Этот тип подхода заключается в том, как LINQ to SQL будет генерировать файлы классов.

4

Вы можете создать адаптер, который обращается к «eat» посредством отражения, бедного-человека утиной типизации:

public class Adapter<T> : IAnimal 
{ 
    private T x; 

    Adapter(T x) 
    { 
    this.x = x; 
    } 

    public void eat() 
    { 
    x.GetType().GetMethod("eat").Invoke(this); 
    } 
} 

Затем вы можете использовать его как это:

dog scruffy = new dog(); 
cat ruffles = new cat(); 

IAnimal[] animals = new IAnimal[] {new Adapter<dog>(scruffy), new Adapter<cat>(ruffles)}; 
+0

, в то время как я думаю, что, вероятно, мне удастся модифицировать мой код, это действительно ответ на мой вопрос. – rizzle

+0

Спасибо, кстати! SO Rocks! – rizzle

+0

Как это работает для свойств? – rizzle

1

Если генератор кода генерирует классы как частичные, вы можете добавить другое частичное определение, которое реализует интерфейс.