Подтвердить что ты не робот

Передача объекта в общий интерфейс

У меня есть следующий интерфейс:

internal interface IRelativeTo<T> where T : IObject
{
    T getRelativeTo();
    void setRelativeTo(T relativeTo);
}

и набор классов, которые (должны) реализовать его, например:

public class AdminRateShift : IObject, IRelativeTo<AdminRateShift>
{
    AdminRateShift getRelativeTo();
    void setRelativeTo(AdminRateShift shift);
}

Я понимаю, что эти три не совпадают:

IRelativeTo<>
IRelativeTo<AdminRateShift>
IRelativeTo<IObject>

но, тем не менее, мне нужен способ работать со всеми различными классами, такими как AdminRateShift (и FXRateShift, DetRateShift), которые должны реализовать IRelativeTo. Скажем, у меня есть функция, которая возвращает AdminRateShift как объект:

IRelativeTo<IObject> = getObjectThatImplementsRelativeTo(); // returns Object

Программируя интерфейс, я могу сделать то, что мне нужно, но я не могу на самом деле отбросить объект в IRelativeTo, чтобы я мог его использовать.

Это тривиальный пример, но я надеюсь, что он разъяснит, что я пытаюсь сделать.

4b9b3361

Ответ 1

Если я понимаю вопрос, то наиболее распространенным подходом было бы объявить не общий базовый интерфейс, т.е.

internal interface IRelativeTo
{
    object getRelativeTo(); // or maybe something else non-generic
    void setRelativeTo(object relativeTo);
}
internal interface IRelativeTo<T> : IRelativeTo
    where T : IObject
{
    new T getRelativeTo();
    new void setRelativeTo(T relativeTo);
}

Другим вариантом является то, что вы в основном кодируете генераторы... т.е. у вас есть методы, такие как

void DoSomething<T>() where T : IObject
{
    IRelativeTo<IObject> foo = // etc
}

Если IRelativeTo<T> является аргументом для DoSomething(), тогда обычно вам не нужно указывать общий аргумент типа самостоятельно - компилятор выведет его - i.e.

DoSomething(foo);

а не

DoSomething<SomeType>(foo);

Есть преимущества для обоих подходов.

Ответ 2

К сожалению, наследование не работает с дженериками. Если ваша функция ожидает IRelativeTo, вы можете сделать ее также общей:

void MyFunction<T>(IRelativeTo<T> sth) where T : IObject
{}

Если я правильно помню, когда вы используете вышеприведенную функцию, вам даже не нужно указывать тип, компилятор должен понять это на основе аргумента, который вы предоставляете.

Если вы хотите сохранить ссылку на один из этих объектов IRelativeTo внутри класса или метода (и вам все равно, что такое T), вам нужно снова создать этот класс/метод.

Я согласен, это немного боль.

Ответ 3

Если вам все равно, что IRelativeTo имеет дело с IObjects, вам не нужно делать его общим:

interface IRelativeTo
 {
   IObject getRelativeTo();
   void setRelativeTo(IObject relativeTo)
 }

Однако классы реализации могут все же быть родовыми:

abstract class RelativeTo<T>  : IRelativeTo where T : IObject
 {  
   public virtual T getRelativeTo() {return default(T);}

   public virtual void setRelativeTo(T relativeTo) {}

   IObject IRelativeTo.getRelativeTo() {return this.getRelativeTo(); }

   void IRelativeTo.setRelativeTo(IObject relativeTo) 
    { this.setRelativeTo((T) relativeTo);
    }
 }

class AdminRateShift :  RelativeTo<AdminRateShift>, IObject {}

Затем вы можете сделать это:

  IRelativeTo irt = new AdminRateShift();
  IObject o = irt.getRelativeTo();
  irt.setRelativeTo(o);