views:

231

answers:

11

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.

+4  A: 

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.

AdamRalph
i'm not being that lazy, see edit
rizzle
ok, but in your original question you just said 'I have 100 classes' you said nothing about them being auto-generated
AdamRalph
OK, point taken. My answer has anyway now been edited to reflect the edited change in the question.
AdamRalph
After trying out reflection, modifying the code gen is what i will do. Thanks!
rizzle
A: 

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.

Sam Meldrum
+10  A: 

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.

Jack Ryan
+1  A: 

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.

Doug T.
But then you'd have to go through the 100 classes and write an adapter for each one. Much more work than simply putting ': IAnimal' after those classes
AdamRalph
-1 Because you double the classes but don't get any benefit.
Outlaw Programmer
Sure it does if you have no ability to modify the cat class and you need to fit it into your framework.
Doug T.
good idea though.
rizzle
he clearly has the ability to modify the classes but is just being lazy
AdamRalph
I'm lazy, I wouldn't want to have to modify all those classes. Especially if it needs to get reautogenerated later for any reason. Then he'd have to reapply any changes.
Doug T.
my comments about being lazy were written before the question was modified to say that the classes were being autogenerated. In this case, the auto-generator needs to be modifed to add the interface implementation where necessary
AdamRalph
+1 This should be the accepted answer.
0xA3
+1  A: 

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.

JoshBerke
A: 

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.

Mehrdad Afshari
I think this would be pretty tough to do with regex alone.
Outlaw Programmer
You basically do a search for "class \w*" and add a ": IAnimal" afterwards.
Mehrdad Afshari
Especially since it would have to examine the methods and properties of each class to see if it can, indeed, implement the interface in question.
AdamRalph
I assumed you already do have the methods implemented. Otherwise, probably an extension method is the way to go.
Mehrdad Afshari
You're really overengineering now. What's wrong with just adding ': IAnimal' to the relevant classes?
AdamRalph
@AdamRalph: If the guy needs to just add a ": IAnimal", the regex would be a good approach. Otherwise, he needs to somehow implement the methods of IAnimal. To do so for a hundred classes, extension methods do really look suitable.
Mehrdad Afshari
the methods are already implemented. He just needs to go through the clases and decide which ones have the necessary methods implemented add ': IAnimal' to the definitions. Anyway, the answer is to modify the code generator.
AdamRalph
A: 

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.

confusedGeek
+6  A: 

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.

ChrisW
nice thinking.. could be a good solution if changing the code generator is too difficult
AdamRalph
very nice solution, we use this with generated code as well
orip
Reflection was a cool idea but kludgy, this was much simpler to implement
rizzle
@rizzle: agreed :)
orip
A: 

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.

Jim Petkus
+4  A: 

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 )};
orip
while i think that i'll probably end up modifying my code gen, this is really the answer to my question.
rizzle
Thanks, btw! SO Rocks!
rizzle
How would it work for properties?
rizzle
Exactly the same way - the properties are translated to set_XXX and get_XXX methods.
Sunny
+1  A: 

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

erikkallen