2

I have a very simple question, but I haven't had this problem before.

Take a look at this code:

interface IFoo
{
    IBar MyBar { get; }
}

interface IBar
{
    String Test { get; }
}

class Foo : IFoo
{
    public Bar MyBar { get; set; }
}

class Bar : IBar
{
    public String Test { get; set; }
}

The problem is that Foo doesn't implement IFoo since it returns Bar rather than IBar. But I don't see the problem since Bar is implementing IBar. Do I miss something?

I want my application to use the class Foo but expose IFoo to other parts of the solution.

This is a way around it, but it seems like an ugly solution:

class Foo : IFoo
{
    public Bar MyBar { get; set; }
    IBar IFoo.MyBar { 
        get { return this.MyBar; }
    }
}

Is this the way to go, or is it a better way?

Olle Johansson
  • 508
  • 3
  • 10
  • 1
    `Bar` is an `IBar`, but `IBar` is not a `Bar`. – Davin Tryon May 03 '13 at 10:57
  • This is called return type covariance and according to [this post](http://stackoverflow.com/questions/5709034/does-c-sharp-support-return-type-covariance) C# and the CLR doesn't support it. – Dirk May 03 '13 at 10:59
  • 3
    The "ugly way around" (also known as the explicit interface implementation) is indeed the only way around this issue in C#. In fact, that's part of the reason the feature exists in the first place. – Sergey Kalinichenko May 03 '13 at 11:00
  • I think your solution (explicit interface) is the preferred way I'd go. Another option since you only have getters is to use `out` generics: `interface IFoo where T : IBar { T MyBar { get; } }` then you can assign foos like: `IFoo f = new Foo();`, but that kind of sucks because you have this useless generic floating around all the time. – Chris Sinclair May 03 '13 at 11:01

2 Answers2

2

You can do this:

interface IFoo<out B> where B:IBar
{
    B MyBar { get; }
}

interface IBar
{
    String Test { get; }
}

class Foo : IFoo<Bar>
{
    public Bar MyBar { get; set; }
}

class Bar : IBar
{
    public String Test { get; set; }
}

This will only work in the case that B is in an output position (for obvious reasons, if you think about it long enough).

Daniel Pratt
  • 12,007
  • 2
  • 44
  • 61
-1

The problem is that Foo doesn't implement IFoo since it returns Bar rather than IBar. But I don't see the problem since Bar is implementing IBar. Do I miss something?

Yes. You're misinterpreting the contract of the IFoo interface. The contract is simple:

One property named MyBar, that has a getter, and has a return type of IBar. The contract isn't that it returns an object that is of type IBar, it's that the return type is type IBar.

This is standard. Try implementing the ICloneable interface, which has a single method, Clone(), with a return type of object. Implementing this interface means you must implement a method with a return type of object, no matter what. Even if you'd rather be a bit more specific, any other return type won't qualify.

The way around it you suggested is one of the right ways to go about it - having an IBar property that returns the Bar property. Or, y'know, you could just have an IBar property and set it to a Bar instance, since that's perfectly valid, and then work with your IBar object through the IBar contract. That would help with decoupling.

doppelgreener
  • 4,809
  • 10
  • 46
  • 63