views:

207

answers:

5

I am working through a bug. In recreating the bug for the following sample I was able to determine why the problem is happening. But I am stuck for a better solution. So given the following program:

public interface IFoo<T> {
    T OutputType(T param);
}

class Foo : IFoo<Foo> {
    public virtual Foo OutputType(Foo param) {
        Console.WriteLine("foo");
        return param;
    }
}

class Bar : Foo, IFoo<Bar> {
    public virtual Bar OutputType(Bar param) {
        Console.WriteLine("bar");
        return param;    
    }
}

class Program {
    static void Main(string[] args) {
        Bar bar = new Bar();
        CallOutputType(bar);
        bar.OutputType(bar);
    }

    static void CallOutputType<T>(T t) where T : Foo {
        t.OutputType(t);
    }      
}

I was expecting the output to be:

bar
bar

But what I am getting is:

foo
bar

Seeing the problem simplified like this it is obvious that Bar.OutputType isn't overriding Foo.OutputType. What are my best options for improving this design? Bar.OutputType can't override Foo.OutputType because the signatures are different. Changing the signature of Bar.OutputType to match Foo.OutputType won't work because then Bar won't be implimenting IFoo.

A: 

How about adding this to the Bar class:

    public override Foo OutputType(Foo param)
    {
        return this.OutputType((Bar)param);
    }
BFree
A: 

How about converting your interface definition such that param's type is declared to extend IFoo?

eqbridges
+5  A: 

Uh, I'm not too familiar with this stuff but shouldn't it be:

static void CallOutputType<T>(T t) where T : IFoo<T>
{
   t.OutputType(t);
}

It worked when I compiled it.

Spencer Ruport
Hmm, I am trying to test this now, what I think I might end up doing is in CallOutputType - ((IFoo<T>)t).OutputType(t); I can't change the method constant for other reasons.
Bob
Thanks for pointing me in the correct direction, using the interface to call the method works.
Bob
A: 

I'd second Spencer on that - when you generic constraint is T : Foo, it typecasts your Bar into a Foo, and obviously you get to call the OutputType method of the Foo class then.

Steffen
A: 

I am not certain what it is you are wanting to accomplish in the end but would this help?

If you add a Generic to what ever implements IFoo then you can specify the type when the derived object is created...

public class Foo<TFoo> : IFoo<TFoo>
{

}

//Then you code would allow this...
//Again other then returning Bar both times I am not certain exactly what you are 
//wanting to accomplish But specifying the type at create will allow you to return Bar 
//even if you created a Foo or a Bar...

class Program {
    static void Main(string[] args) {
        Foo foo = new Foo<Bar>();
        CallOutputType(foo);
        foo.OutputType(foo);
    }

    static void CallOutputType<T>(T t) where T : Foo {
        t.OutputType(t);
    }      
}
J.13.L