tags:

views:

123

answers:

4

I want to make an interface in C# that defines a method that always returns an object of the implementing class, thus:

public interface IParser {
    IParser Parse(string s);
}

public class Parser : IParser {
    public Parser Parse(string s) {
        return new Parser(s);
    }
}

Can I force an implementing class to return an object of its own type? If possible, then how? Or is generics the answer here?

NB: The code is just an illustration, not something that's supposed to run.

+1  A: 

Yes, and this is known as the factory pattern, only that usually this is complemented with the use of a private constructor and making the instance returning method static, for example:

public class Parser : IParser {

    private Parser(string s) {
        //Do something with s, probably store it in a field
    }

    public static IParser GetNewParser(string s) {
        return new Parser(s);
    }
}
Konamiman
I think the key is the phrase "... force an implementing class to return an object of its own type ..."
Matt Breckon
This really wasn't a "yes/no" question. I want to concretely know how this is done in C#, if it is possible.
Cros
+7  A: 

Generics is the answer here.

public interface IParser<T> where T:IParser<T> {
    T Parse(string s);
}

public class Parser : IParser<Parser> {
    public Parser Parse(string s) {
        return new Parser(s);
    }
}
BennyM
Good work... I was just testing my code out for the same thing. +1
jheddings
I'm gonna try that immediately.
Cros
Seems that when you make the interface generic like this, you have to specify T everywhere you use ISelection as a specifier for the type you use, e.g. I can't now make just a List<IParser> but now it has to be a List<IParser<Parser>>. Am I correct? Then this isn't the solution I'm looking for, sadly.
Cros
While this works perfectly well, I'd recommend revising your design to return the interface type (IParser). Most of the time, this kind of usage defies the purpose of the interface. Plus, working with IParser<T> makes it that much more difficult to pass it around.
Bryan Menard
It does indeed enforce you to specify the type everywhere now, but it does answer your question. Personally I'd return the IParser interface in the Parse method too.You can mix both though, create an IParser interface and let IParser<T> inherit from it.
BennyM
I'm going to mark this as accepted since it's closest to what I intended, and it also answers my question where the answer is "no".I'm going to let my Parse method return an IParser, since that is the better design. Thanks!
Cros
A: 

You can do this with Generics, but I would probably stick with returning an instance of the interface. Note that since the class implements the interface, returning an instance of it is ok -- it will be an instance of that type and of the interface as well.

public class Parser : I Parser
{
   public IParser Parser( string s )
   {
       return Parser(s);
   }
}
tvanfosson
+5  A: 

Not in the interface declaration, no. The best you could manage is with generics:

public interface IParser<T>
    where T: IParser<T>
{
    T Parse(string s);
}

public class Parser
 : IParser<Parser>
{
    public Parser Parse(string s)
    {
       return new Parser(s);
    }
}

This doesn't force the implementation to return it's own type, but at least it allows it to do so. This is why the IClonable interface returns an object from its Clone method, rather than a specific type.

----Edit----

Something to remember on this question: let's say that my code, for which you don't have any knowledge of the implementation, returns an IParser, and your code calls the Parse method. What object do you expect to be returned, not knowing the concrete type of returned IParser reference? I think you're trying to use interfaces for something they're not meant to do...

FacticiusVir
+1 for mentioning this technique does not force the requested implementation. You could just as easily return another IParser<T> implementation. AFAIK there is no way to enforce this check at the language level; this is the closest thing you'll get to it.
Programming Hero