C#声明了两者,类和接口

时间:2013-10-29 14:11:56

标签: c# interface declaration encapsulation

// 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; }
}

我应该把什么?强制继承AnimalIHasLegs的对象?我不希望在该网箱中看到Snake也不是Table

--------------编辑--------------

谢谢大家的答案,但事情是这样的: 我真正想做的是:

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

TextBox / ComboBox当然是一个控件。 现在,如果我创建一个继承Control和IClonable的抽象类,我将松开我需要的TextBox / ComboBox继承。不允许多类继承,因此我必须使用接口。现在我再次想到它,我可以创建另一个继承自IClonable的接口:

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

然后

List<IClonableControl> clonableControls;

谢谢!

6 个答案:

答案 0 :(得分:17)

首先,Animals对于类名来说是一个糟糕的选择,它将是Animal。类名应该是单数。此类也应声明为abstract,因为它只是Donkey等具体类型的基类。

其次,您可以定义一个名为LeggedAnimal的抽象类,该类继承自AnimalIHasLegs。然后,您可以从Donkey等继承LeggedAnimal

最后,你可以说List<LeggedAnimal>,你就可以了!

答案 1 :(得分:10)

没有List<T where T : Animals, IHasLegs>的直接概念。您可以将T向上移动到一个级别 - 然后调用者必须指定满足两个约束的单个T

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

例如,它可能是Cage<Lizard> - 或(单独)Cage<Donkey> - 但您仍然无法使用它来存储 任何 Animal有腿 - 即你不能使用这个概念将LizardDonkey放在同一个笼子里。

答案 2 :(得分:3)

  1. 我认为Animal是一个抽象类,因此需要被称为IAnimal。
  2. 创建一个继承自IhasLegs和IAnimal的新类型IAnimalWithLegs。
  3. 使用新创建的类型作为列表类型。

答案 3 :(得分:3)

为什么不制作AnimalwithLegs类?

public abstract class AnimalWithLegs : Animal, IHasLegs{}

然后

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

答案 4 :(得分:1)

给你一个完整的例子..复制粘贴到Visual-Studio并编译。祝你好运:)

 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,
            };
        }

    }

答案 5 :(得分:0)

如果您感兴趣的类型的合理数量组合是一种方法,那就是定义从多个接口继承的复合接口。可以为任何接口组合定义复合接口,并使用这种类型作为通用参数。这种方法最大的问题是,即使像IFooBar这样的界面只是IFooiBar并且没有宣布自己的成员,也没有办法指明,这意味着任何实现IFooIBar的类实现了IFooBar的所有成员,它们不允许将这些类强制转换为IFooBar除非他们宣称自己是在实施它。因此,在定义实现接口组合的类之前,必须确定一个人感兴趣的接口组合,如果这些类可以被期望这些组合的代码使用。

另一种方法是定义接口ISelf<out T> { T Self {get;}},对于许多其他接口(例如IAnimal),也可以定义例如IAnimalAnd<out T> : IAnimal, ISelf<T> { }Zebra,并且有任何类型,例如例如IAnimal IAnimalAnd<Zebra>也实施Animal。如果一个人使用该模式并且需要一个已知支持IWagTailIMooIGiveMilk的{​​{1}}列表,那么执行这些操作的任何Animal根据模式将实现IWagTailAnd<IMooAnd<IGiveMilkAnd<Animal>>>>(可以按任何顺序嵌套接口)。如果其中一个具有该类型的引用it,那么it将实施IWagTailit.Self将实施IMooit.Self.Self将实施IGiveMilk 1}},it.Self.Self.Self将是Animal。如果it以通常的方式实现模式,则所有上述引用都将引用相同的对象实例it,但是作为不同的类型。

对此方法有用的是,使用此模式实现任何接口组合的对象可以转换为嵌套接口类型,表示这些类型的任何子集,无论是否有人认为该特定子集将是在写入类型时很有用。这种方法最大的困难在于即使实现IWagTailAnd<IGiveMilkAnd<Animal>>的对象应该同时实现IWagTailIGiveMilk,编译器也无法告诉它;它可以告诉对象实现IWagTail,并且它的Self属性实现IGiveMilk,并且可能期望模式的正常实现,即对象{{1} }属性将引用自身(暗示它必须实现Self),但编译器无法知道。