robertkroll
robertkroll

Reputation: 8794

Casting an object to a generic interface

I have the following interface:

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

and a bunch of classes that (should) implement it, such as:

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

I realise that these three are not the same:

IRelativeTo<>
IRelativeTo<AdminRateShift>
IRelativeTo<IObject>

but nonetheless, I need a way to work with all the different classes like AdminRateShift (and FXRateShift, DetRateShift) that should all implement IRelativeTo. Let's say I have a function which returns AdminRateShift as an Object:

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

By programming against the interface, I can do what I need to, but I can't actually cast the Object to IRelativeTo so I can use it.

It's a trivial example, but I hope it will clarify what I am trying to do.

Upvotes: 34

Views: 31698

Answers (3)

Mark Cidade
Mark Cidade

Reputation: 100047

If all you care about is that IRelativeTo deals with IObjects then you don't need to make it generic:

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

The implementing classes may still be generic, however:

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 {}

Then you can do this:

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

Upvotes: 7

Marc Gravell
Marc Gravell

Reputation: 1064184

If I understand the question, then the most common approach would be to declare a non-generic base-interface, i.e.

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

Another option is for you to code largely in generics... i.e. you have methods like

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

If the IRelativeTo<T> is an argument to DoSomething(), then usually you don't need to specify the generic type argument yourself - the compiler will infer it - i.e.

DoSomething(foo);

rather than

DoSomething<SomeType>(foo);

There are benefits to both approaches.

Upvotes: 32

Grzenio
Grzenio

Reputation: 36679

unfortunately inheritance doesn't work with generics. If your function expects IRelativeTo, you can make the function generic as well:

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

If I remember correctly, when you use the function above you don't even need to specify the type, the compiler should figure it out based on the argument you supply.

If you want to keep a reference to one of these IRelativeTo objects inside a class or method (and you don't care what T is that), you need to make this class/method generic again.

I agree, it is a bit of pain.

Upvotes: 14

Related Questions