Reputation: 1248
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();
}
Upvotes: 9
Views: 5378
Reputation: 172260
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 C++ 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 as well as a "this" type are proposed features for new versions of C#:
Upvotes: 11
Reputation: 68466
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
.
Upvotes: 9
Reputation: 4206
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?
Upvotes: 4
Reputation: 7199
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
Upvotes: 2
Reputation: 1295
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
}
Upvotes: 0
Reputation: 887433
You need to make the interface generic, like this:
interface IFoo<TClass> where TClass : IFoo<TClass>, class {
TClass Bar();
}
Upvotes: 0
Reputation: 245419
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();
}
}
Upvotes: 0