2016-03-18 1 views
1

Допустим, у меня есть абстрактный класс 2 интерфейса:Дайте компиляции ошибки времени, если два класса не реализует тот же интерфейс

public abstract class Entity 
{ 
    public abstract void Interact(Entity entity); 
} 

public interface IFoo 
{ 
    void DoFoo(); 
} 

public interface IBar 
{ 
    void DoBar(); 
} 

И сейчас, скажем, у меня есть два класса, которые реализуют эти интерфейсы:

public class Foo : Entity, IFoo 
{ 
    public override void Interact(Entity entity) 
    { 
     // do something with entity... 
    } 

    public void DoFoo() 
    { 
     // Do foo stuff here.. 
    } 
} 

public class Bar : Entity, IBar 
{ 
    public override void Interact(Entity entity) 
    { 
     // do something with obj.. 
    } 

    public void DoBar() 
    { 
     // Do bar stuff here.. 
    } 
} 

Теперь вопрос, поскольку эти классы реализуют тот же абстрактный класс (Entity), можно для Bar взаимодействовать с Foo или наоборот, что-то вроде этого:

var foo = new Foo(); 
var bar = new Bar(); 

foo.Interact(bar); // OK! 
bar.Interact(foo); // OK too! 

Но теперь, я хочу Foo только в состоянии взаимодействовать с другим экземпляром IFoo и дать компиляции ошибки времени, если он пытается взаимодействовать с экземпляром Bar, то же правило должно применяться к Bar тоже. Поэтому это должно быть что-то вроде.

var foo = new Foo(); 
var anotherFoo = new Foo(); 
var bar = new Bar(); 

foo.Interact(anotherFoo); // OK! 
foo.Interact(bar); // give compile time error 
bar.Interact(foo); // this one should give compile time error too 

Можно ли это сделать? Если да, то как я могу это сделать?

+0

Просто заметка на полях: Декларация метода 'Interact()' внутри класса 'Entity'. Это должна быть «публичная абстракция». –

+0

Вы можете проверить тип внутри метода 'Interact()' метод и бросить 'ArgumentException', если тип не тот, который вы ожидаете. – Alex

+0

@FlatEric спасибо за исправление! Я обновил вопрос – SirusDoma

ответ

2

вы смешиваете несколько элементов здесь

Entity не имеет никакого отношения к IFoo или IBar
Foo имеет отношения с Entity и IFoo Bat имеет отношения с Entity и IBar

так что если вы только хотят взаимодействовать с IFoo, то вам необходимо указать IFoo в качестве родителя не сущности

public class Foo : Entity, IFoo 
{ 
    public void Interact(IFoo entity) 
    { 
     // do something with entity... 
    } 

    public void DoFoo() 
    { 
     // Do foo stuff here.. 
    } 
} 

public class Bar : Entity, IBar 
{ 
    public void Interact(IBar entity) 
    { 
     // do something with obj.. 
    } 

    public void DoBar() 
    { 
     // Do bar stuff here.. 
    } 
} 

как поведение взаимодействуют между собой не разделяемой всеми своими детьми т огда взаимодействуют не принадлежит родителю

вы можете обойти это с дженериков, хотя

public abstract class Entity<T> 
where T:Entity 
{ 
    void Interact(T entity); 
} 

это позволит затем объявлять Foo, как

public class Foo : Entity<Foo>, IFoo 
{ 
    public override void Interact(Foo entity) 
    { 
     // do something with entity... 
    } 

    public void DoFoo() 
    { 
     // Do foo stuff here.. 
    } 
} 
+0

Спасибо за ответ и объяснение! Родовые - это то, чего я хочу. Однако можно ли добавить на него больше «ограничений»? например, у меня есть еще два класса под названием «FooBar: Entity , IFoo, IBar' и« BarFoo: IFoo, IBar », тогда я хочу, чтобы класс FooBar мог« взаимодействовать »с другим классом, который реализует« IFoo »и Другими словами, он может взаимодействовать с другим экземпляром «FooBar», экземпляром BarFoo и любым классом, который реализует интерфейсы «IFoo» и «IBar». Является ли это возможным? какой общий параметр следует передать в 'Entity <>'? – SirusDoma

+0

, если вы укажете, где T: IFoo, тогда T может быть любым классом, который реализует интерфейс foo.однако в этом случае вы, вероятно, захотите переместить взаимодействие в интерфейс Foo, а затем создать simalar-метод в интерфейсе бара, который принимает только вход IBar, если это не работает, тогда вам придется принять, что ваш код не может быть проверяется при компиляции и требует проверок времени выполнения, поскольку другие ответы предлагают – MikeT

+0

, вы также можете создать интерфейс IEntity, который наследует Entity, а также IBar и IFoo, тогда вы можете установить, где T: IEntity, что позволило бы IFoo и I bar, поскольку они оба наследуют от IEntity, но не сущность – MikeT

Смежные вопросы