views:

146

answers:

7

I have a situation where i have a class

class Foo
{
    Foo Bar()
    {
        return new Foo();
    }
}

Now i wan tot create an interface for it

class IFoo
{
    ??? Bar();
}

What should be in place of the question marks? Each class should return it's own type, not Foo.

The solutions below work but do not looks clean. I don't understand why i have to specify the same class twice, and there is nothing like "this" for the current type

This is how i am using it later

class GenericClass<T> where T : IFoo
{ 
    T foo = new T();
    T item = foo.Bar();
}
+8  A: 

You could add a generic type and constrain it using the interface type:

public interface IFoo<T>
{
    T Bar();
}

You'd implement this as follows:

public class Foo : IFoo<Foo>
{
    public Foo Bar()
    {
        return new Foo();
    }
}

public class Cheese : IFoo<Cheese>
{
    public Cheese Bar()
    {
        return new Cheese();
    }
}

Update, if you never care about the concrete return type of Foo, then you can do the following:

public interface IFoo
{
    IFoo Bar();
}

Which is implemented like:

public class Foo : IFoo
{
    public IFoo Bar()
    {
        return new Foo();
    }
}

Then in your generic class:

public class GenericClass<T> where T : class, IFoo, new()
{
    public T Rar()
    {
        T foo = new T();
        T item = foo.Bar() as T;
        return item;
    }
}

GenericClass<Foo>.Rar(); will be a concrete implementation of Foo.

GenericTypeTea
This will not compile.
SLaks
@SLaks: He just needs to add `public`, right?
Dan Tao
Looks fine to me. Why shouldn't it compile?
jalf
@GenericTypeTea, @jalf: For `Foo` to implement `IFoo<Foo>` its implementation methods (in this case: `Bar`) need to be `public`. That's all, as far as I can tell.
Dan Tao
Actually, I think Slaks may have written that comment while I was editing the answer. I originally wrote it with a constraint saying `where T : IFoo`.
GenericTypeTea
@GenericTypeTea: That makes sense. You still need `public`, though (it really won't compile without it, so SLaks's comment is still true).
Dan Tao
It doesn't necessarily need to be public, could be declared privately with Foo IFoo<Foo>.Bar(), but yeah, as it is, it won't compile.
Mark H
@All - Fixed! Woops.
GenericTypeTea
@GenericTypeTea, the constraint would work if its where T : IFoo<T>, this self-constraint is used extensively throughout the CSLA.NET framework actually.
Adam
@Adam - am I getting confused with constraints? Do you mean you can still use IFoo.Method()? Not got visual studios open to test.
GenericTypeTea
@GenericTypeTea Its saying that T can only be types that implement IFoo<T>, which is always going to be the case, come to think of it. Any other types would generate compiler errors.
Adam
@adam - Yea, so you can never use IFoo. It can only be used as IFoo<Foo> foo = new Foo();. Like you said, big code smell!
GenericTypeTea
@GenericTypeTea - The constraint is to restrict the types that IFoo can be implemented with. In the current form, you'd be able to write `class Foo2 : IFoo<int> {`, and your Bar method would now return an int, which isn't what is wanted by the description. Bar should only ever return a type derived from IFoo, so the constraint `interface IFoo<T> where T : IFoo<T>` should be used.
Mark H
I wouldn't call it a *big* code smell :) It allows you to introduce strong typing into your interface implementation (and is used in the .NET Framework itself), but you lose the polymorphic behaviour of the interface - which is arguably one of the first reasons for defining it. Not sure where any of this discussion stands with the introduction of contra/co-variance in .NET 4 lol
Adam
A: 
public interface IFoo<T>
{
    T Bar();
}

Your implementation would then be:

class Foo : IFoo<Foo>
{
    Foo Bar()
    {
        return new Foo();
    }
}

class Baz : IFoo<Baz>
{
    Baz Bar()
    { 
        return new Baz(); 
    }
}
Justin Niessner
A: 

You need to make the interface generic, like this:

interface IFoo<TClass> where TClass : IFoo<TClass>, class {
    TClass Bar();
}
SLaks
+2  A: 

You can use an abstract base class plus explicit member implementation to achieve this. First, declare your interface like this:

interface IFoo
{
    IFoo Bar();
}

Then, declare a generic abstract class that implements IFoo in an explicit manner, and also declares an abstract method that kind of "overloads" Bar(), but in a generic manner:

abstract class BaseFooImpl<T> : IFoo where T : BaseFooImpl
{
    public abstract T Bar();

    IFoo IFoo.Bar()
    {
        return Bar(); // this will call the abstract Bar()
    }
 }

Now, define your concrete classes like this:

class ConcreteFoo : BaseFooImpl<ConcreteFoo>
{
   public override ConcreteFoo Bar()
   {
      return this; // for example, of course.
   }
}

The advantage of this approach is that you can always use non-generic IFoo references to hold concrete instances. If you make your interface generic, you can't, for instance, declare these:

IFoo mammalInstance, fishInstance; // Instead of IFoo<Mammal> mammalInstance; IFoo<Fish> fishInstance;
List<IFoo> manyInstances; // Instead of List<IFoo<IFoo>>, which doesn't even work AFAIK
Humberto
And what prevents someone from saying class C2 : BaseFooImpl<ConcreteFoo> ? Nothing. This does not constrain Bar to return C2.
Eric Lippert
@Eric, that's unsettling. It even invalidates my answer, if we stick to the needs of the OP. I guess this problem is common to the others solutions posted here too. However, `C2` (or better, its author) knows what it is doing.
Humberto
A: 

Not sure what you are trying to accomplish but it could be done this way:

interface IFoo<T>
{
    T Bar();
}



   class Foo:IFoo<Foo>
    {

        #region IFoo<Foo> Members

        public Foo Bar()
        {
            return new Foo();
        }

        #endregion
    }

Or Like this:

    interface IFoo
    {
        IFoo Bar();
    }

class Foo : IFoo
    {

        #region IFoo Members

        public IFoo Bar()
        {
            return new Foo();
        }

        #endregion
    }
CkH
+2  A: 

You ask:

The solutions below work but do not looks clean. I don't understand why i have to specify the same class twice, and there is nothing like "this" for the current type

The reason why you have to specify it twice is because C# lacks the feature that you need. What you want is something like this:

interface IFoo
{
    IFoo Bar();
}

class Foo : IFoo
{
    Foo Bar() // should work since Foo is an IFoo, but it's not supported by C#
    {
        return new Foo();
    }
}

From a type-safety point of view, this should work (it's called return type covariance). In fact, other programming languages such as D or Java support this, see this example on Wikipedia. Unfortunately, return type covariance is not supported by C# (not even C# 4.0, which introduced covariance for generics), which is why you have to use the "generics workaround" illustrated in the other answers.

Covariant return types are a highly requested feature in C#, see MS Connect Bug 90909.

Heinzi
Your code won't compile because the class Foo does not implement `IFoo Bar()`. You can modify Foo this to make Bar return an IFoo, but it'll mean you need to upcast the IFoo to Foo anywhere you might want to access Foo's methods. (although safe to do, not very tidy to write). <br/>Covariance and contravariance are supported in generic types as of C# 4.0, but they're not really necessary for this scenario. The solution GenerticTypeTea posted is sufficient.
Mark H
@Mark H - I think what Heinzi is saying is saying is "this is what the OP wants... however it's not possible".
GenericTypeTea
@GenericTypeTea: Exactly. :-) Actually, I'm saying "It's not possible in C# (but in other languages)."
Heinzi
@MarkH: Covariance (in the sense that Java has it -- not just generic covariance like C# 4.0 but also return type covariance) would allow my code example to work, eliminating the need for using generics in this case.
Heinzi
+4  A: 

I think that the real question is: why you need the derived type in the interface? Interface is exactly for that reason - abstracting from the concrete classes. If it's just for convenience, so you don't have to cast to Foo after calling Bar(), you can implement the interface explicitly:

interface IFoo
{
    IFoo Bar();
}

class Foo : IFoo
{
    public Foo Bar()
    {
        return new Foo();
    }

    IFoo IFoo.Bar()
    {
        return Bar();
    }
}

Ask yourself the question: why do you introduce an interface when you want the concrete type?

Stefan
+1 This is exactly what I was thinking.
juharr
To give a simple example: This object is later used to bind a grid. At that point i do not use the interface that only covers the crud, but instead depend on properties that represent columns
Andrey