Question

// interface
public interface IHasLegs { ... }

// base class
public class Animal { ... }

// derived classes of Animal
public class Donkey : Animal, IHasLegs { ... } // with legs
public class Lizard : Animal, IHasLegs { ... } // with legs
public class Snake : Animal { ... } // without legs

// other class with legs
public class Table : IHasLegs { ... }

public class CageWithAnimalsWithLegs {
    public List<??> animalsWithLegs { get; set; }
}

What should I put in the ?? to force objects that inherit from both Animal and IHasLegs? I don't want to see a Snake in that cage neither a Table.

-------------- EDIT --------------

Thank you all for your answers, but here is the thing: What I actually want to do is this:

public interface IClonable { ... }
public class MyTextBox : TextBox, IClonable { ... }
public class MyComboBox : ComboBox, IClonable { ... }

TextBox/ComboBox is of course a Control. Now if I make an abstract class that inherits both Control and IClonable, I will loose the TextBox/ComboBox inheritance that I need. Multiple class inheritance is not allowed, so I have to work with interfaces. Now that I think of it again, I could create another interface that inherits from IClonable:

public interface IClonableControl : IClonable { ... }
public class MyTextBox : TextBox, IClonableControl { ... }
public class MyComboBox : ComboBox, IClonableControl { ... }

and then

List<IClonableControl> clonableControls;

Thank you!!

Was it helpful?

Solution 3

Why Don't you make a class AnimalwithLegs?

public abstract class AnimalWithLegs : Animal, IHasLegs{}

then

public class CageWithAnimalsWithLegs 
{
   public List<AnimalWithLegs>  AnimalWithLegs { get; set; }
}

OTHER TIPS

First of all, Animals is a bad choice for a class name, it would be Animal. Class names should be in singular. This class should also be declared abstract, because it is just a base class for concrete types such as Donkey.

Second, you can define an abstract class named LeggedAnimal that inherits from Animal and IHasLegs. And then you can inherit Donkey from LeggedAnimal, etc.

Finally, you can then say List<LeggedAnimal> and you're good to go!

There is no direct concept of a List<T where T : Animals, IHasLegs>. You can move the T up a level, to the cage - but then the caller must specify an individual T that satisfies both constraints:

class Cage<T> where T : Animal, IHasLegs {
    public List<T> Items {get;set;}
}

It could be a Cage<Lizard>, for example - or (separately) a Cage<Donkey> - but you still could not use this to store any Animal that has legs - i.e. you couldn't put a Lizard and a Donkey in the same cage using this concept.

  1. I think that Animal is an abstract class and hence needs to be called IAnimal.
  2. Create a new type IAnimalWithLegs that inherits from both IhasLegs and IAnimal.
  3. Use the newly created type as the type of the list.

Gave you a full example.. copy-paste to Visual-Studio and compile. Good Luck :)

 internal class Program
    {
        // interface
        public interface IHasLegs {}

        // base class
        public class Animal {}

        public class AnimalWithLegs : Animal, IHasLegs {}

        // Animals
        public class Donkey : AnimalWithLegs {}

        public class Lizard : AnimalWithLegs {}

        public class Snake : Animal {}

        // example of inanimte objects. (lifeless)
        public class Table : IHasLegs {}

        public class Desk : Table {}

        public class ConferenceTable : Table {}

        //public class Wife : BrainLessObject{} //hmm.. wrong place.. dilemma..

        //example for cages
        public class ListOfIhasLegs : List<IHasLegs> {}

        public class ListOfAnimals : List<Animal> {}

        public class ListOfAnimalsWithLegs : List<AnimalWithLegs> {}

        // usage examples.
        private static void Main(string[] args)
        {
            var donkeyInstance = new Donkey();
            var lizardInstance = new Lizard();
            var snakeInstance = new Snake();

            var tableInstance = new Table();
            var deskInstance = new Desk();
            var conferenceTalbeInstance = new ConferenceTable();

            var listOfThingsWithLegs = new ListOfIhasLegs
            {
                donkeyInstance,
                lizardInstance,
                tableInstance,
                deskInstance,
                conferenceTalbeInstance
            };

            var listOfAnimals = new ListOfAnimals
            {
                donkeyInstance,
                lizardInstance,
                snakeInstance
            };

            var cageOfAnimalsWithLegs = new ListOfAnimalsWithLegs
            {
                donkeyInstance,
                lizardInstance,
            };
        }

    }

One approach if there's a reasonable number of combinations of types you're interested in is to define composite interfaces which inherit from multiple interfaces. One may define a composite interface for any combination of interfaces, and use such a type as a generic parameter. The biggest problem with this approach is that there's no way to specify that even if an interface like IFooBar simply IFoo and iBar and declares no members of its own, meaning any class which which implements IFoo and IBar implements all the members of IFooBar, that won't allow such classes to be cast to IFooBar unless they declare themselves as implementing it. Consequently, one must decide what combinations of interfaces one is interested in before defining classes that implement those combinations of interfaces, if those classes are to be usable by code expecting those combinations.

An alternative approach is to define an interface ISelf<out T> { T Self {get;}}, and for many of your other interfaces (e.g. IAnimal) also define e.g. IAnimalAnd<out T> : IAnimal, ISelf<T> { }, and have any type e.g. Zebra which implements e.g. IAnimal also implement IAnimalAnd<Zebra>. If one uses that pattern and needs a list of Animal which are known to support IWagTail, IMoo, and IGiveMilk, then any Animal which does those things according to the pattern will implement IWagTailAnd<IMooAnd<IGiveMilkAnd<Animal>>>> (one may nest the interfaces in any order). If one has a reference it of that type, then it will implement IWagTail, it.Self will implement IMoo, it.Self.Self will implement IGiveMilk, and it.Self.Self.Self will be an Animal. If it implements the pattern in the usual fashion, all of the above references will refer to the same object instance it, but as different types.

What's helpful with this approach is that an object which implements any combination of interfaces using this pattern may be cast to nested interfaces type which represents any subset of those types, whether or not anyone thought that particular subset would be useful when the type was written. The biggest difficulty with this approach is that even though an object which implements IWagTailAnd<IGiveMilkAnd<Animal>> is expected to implement both IWagTail and IGiveMilk, the compiler can't tell that; it can tell that the object implements IWagTail, and that its Self property implements IGiveMilk, and one might expect that normal implementations of the pattern, the object's Self property will refer to itself (implying that it must implement IGiveMilk), but the compiler can't know that.

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