Question

I have a 100 classes that have some similar elements and some unique. I've created an interface that names those similar items eg: interface IAnimal. What i would normally do is:

class dog : IAnimal

But there are 100 classes and i don't feel like going though them all and looking for the ones that i can apply IAnimal to.

What i want to do is this:

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

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

or

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

then do

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

Is there a way to make c# let me treat ruffles and scruffy as an IAnimal without having to write : IAnimal when writing the class.

Thanks!

EDIT (not lazy): The classes are generated off of sql stored proc metadata, which means every time it gets generated i would have to go back and add them in,or modify the code generator to identify the members that are in the interface, actually thats not a bad idea. I was hoping there was some sort of generics approach or something though.

Was it helpful?

Solution

You might solve this problem with partial classes: let the machine-generated/regenerated code be in one source file of each class, and the hand-coded part (defining the subclassing from IAnimal) in another.

OTHER TIPS

What you are asking for is called duck typing and is not part of C# I am afraid. Any solution will involve reflection and looking at the properties, It will be quicker to check the classes by hand I think.

It would be an interesting project to try though.

The solution is to modify the code generator. Currently it's too simplistic for your needs. It should add the interface implementation if the relevant properties and/or methods are present in the class.

You could create an adapter that accesses "eat" through reflection, a poor-man's duck typing:

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

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

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

Then you can use it like this:

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

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

Not easily that I am aware of, you could do a late binding call using reflection but you'd be better of spending your time editing the classes or writting a macro to do it.

Assuming you really can't modify the cat class for good reasons,

You could write an adapter for cat that inherited from IAnimal ie:

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

  }

In C++ you could use templates assuming all your generated classes need to have the same function called:

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

  }

Maybe someone more C#-py than me can do the same with reflection.

If the code generator generates the classes as partial, you can add another partial definition which implements the interface.

No. There is no way you can get C# to let you do this without either having a concrete base class or having an interface.

Your classes have to implement the interface IAnimal. A method/property of the same name on two different classes are not considered equivalent unless they are both implementations of an interface/base class.

If you have already implemented the method and you just want to implement the interface, you can use a regular expression with replace in files command in your IDE.

Otherwise, take a look at extension methods. They might fit your need.

If you implement the generated classes as partial classes, you could implement the interfaces on the these classes and then change your code generator to only generate half of the partial class. This would allow you to regenerate your classes without losing the interface implementation (or any other custom logic you decide to add).

This type of approach is how LINQ to SQL would generate class files.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top